| 1 | /* $NetBSD: zone.c,v 1.5 2019/04/28 00:01:14 christos Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
| 5 | * |
| 6 | * This Source Code Form is subject to the terms of the Mozilla Public |
| 7 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 8 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 9 | * |
| 10 | * See the COPYRIGHT file distributed with this work for additional |
| 11 | * information regarding copyright ownership. |
| 12 | */ |
| 13 | |
| 14 | /*! \file */ |
| 15 | |
| 16 | #include <config.h> |
| 17 | |
| 18 | #include <errno.h> |
| 19 | #include <inttypes.h> |
| 20 | #include <stdbool.h> |
| 21 | |
| 22 | #include <isc/file.h> |
| 23 | #include <isc/hex.h> |
| 24 | #include <isc/mutex.h> |
| 25 | #include <isc/pool.h> |
| 26 | #include <isc/print.h> |
| 27 | #include <isc/random.h> |
| 28 | #include <isc/ratelimiter.h> |
| 29 | #include <isc/refcount.h> |
| 30 | #include <isc/rwlock.h> |
| 31 | #include <isc/serial.h> |
| 32 | #include <isc/stats.h> |
| 33 | #include <isc/stdtime.h> |
| 34 | #include <isc/strerr.h> |
| 35 | #include <isc/string.h> |
| 36 | #include <isc/taskpool.h> |
| 37 | #include <isc/thread.h> |
| 38 | #include <isc/timer.h> |
| 39 | #include <isc/util.h> |
| 40 | |
| 41 | #include <dns/acl.h> |
| 42 | #include <dns/adb.h> |
| 43 | #include <dns/callbacks.h> |
| 44 | #include <dns/catz.h> |
| 45 | #include <dns/db.h> |
| 46 | #include <dns/dbiterator.h> |
| 47 | #include <dns/dlz.h> |
| 48 | #include <dns/dnssec.h> |
| 49 | #include <dns/events.h> |
| 50 | #include <dns/journal.h> |
| 51 | #include <dns/keydata.h> |
| 52 | #include <dns/keytable.h> |
| 53 | #include <dns/keyvalues.h> |
| 54 | #include <dns/log.h> |
| 55 | #include <dns/master.h> |
| 56 | #include <dns/masterdump.h> |
| 57 | #include <dns/message.h> |
| 58 | #include <dns/name.h> |
| 59 | #include <dns/nsec.h> |
| 60 | #include <dns/nsec3.h> |
| 61 | #include <dns/peer.h> |
| 62 | #include <dns/private.h> |
| 63 | #include <dns/rcode.h> |
| 64 | #include <dns/rdata.h> |
| 65 | #include <dns/rdataclass.h> |
| 66 | #include <dns/rdatalist.h> |
| 67 | #include <dns/rdataset.h> |
| 68 | #include <dns/rdatasetiter.h> |
| 69 | #include <dns/rdatastruct.h> |
| 70 | #include <dns/rdatatype.h> |
| 71 | #include <dns/request.h> |
| 72 | #include <dns/resolver.h> |
| 73 | #include <dns/result.h> |
| 74 | #include <dns/rriterator.h> |
| 75 | #include <dns/soa.h> |
| 76 | #include <dns/ssu.h> |
| 77 | #include <dns/stats.h> |
| 78 | #include <dns/time.h> |
| 79 | #include <dns/tsig.h> |
| 80 | #include <dns/update.h> |
| 81 | #include <dns/xfrin.h> |
| 82 | #include <dns/zone.h> |
| 83 | #include <dns/zoneverify.h> |
| 84 | #include <dns/zt.h> |
| 85 | |
| 86 | #include <dst/dst.h> |
| 87 | |
| 88 | #include "zone_p.h" |
| 89 | |
| 90 | #define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E') |
| 91 | #define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC) |
| 92 | |
| 93 | #define NOTIFY_MAGIC ISC_MAGIC('N', 't', 'f', 'y') |
| 94 | #define DNS_NOTIFY_VALID(notify) ISC_MAGIC_VALID(notify, NOTIFY_MAGIC) |
| 95 | |
| 96 | #define STUB_MAGIC ISC_MAGIC('S', 't', 'u', 'b') |
| 97 | #define DNS_STUB_VALID(stub) ISC_MAGIC_VALID(stub, STUB_MAGIC) |
| 98 | |
| 99 | #define ZONEMGR_MAGIC ISC_MAGIC('Z', 'm', 'g', 'r') |
| 100 | #define DNS_ZONEMGR_VALID(stub) ISC_MAGIC_VALID(stub, ZONEMGR_MAGIC) |
| 101 | |
| 102 | #define LOAD_MAGIC ISC_MAGIC('L', 'o', 'a', 'd') |
| 103 | #define DNS_LOAD_VALID(load) ISC_MAGIC_VALID(load, LOAD_MAGIC) |
| 104 | |
| 105 | #define FORWARD_MAGIC ISC_MAGIC('F', 'o', 'r', 'w') |
| 106 | #define DNS_FORWARD_VALID(load) ISC_MAGIC_VALID(load, FORWARD_MAGIC) |
| 107 | |
| 108 | #define IO_MAGIC ISC_MAGIC('Z', 'm', 'I', 'O') |
| 109 | #define DNS_IO_VALID(load) ISC_MAGIC_VALID(load, IO_MAGIC) |
| 110 | |
| 111 | /*% |
| 112 | * Ensure 'a' is at least 'min' but not more than 'max'. |
| 113 | */ |
| 114 | #define RANGE(a, min, max) \ |
| 115 | (((a) < (min)) ? (min) : ((a) < (max) ? (a) : (max))) |
| 116 | |
| 117 | #define NSEC3REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) |
| 118 | |
| 119 | /*% |
| 120 | * Key flags |
| 121 | */ |
| 122 | #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0) |
| 123 | #define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0) |
| 124 | #define ALG(x) dst_key_alg(x) |
| 125 | |
| 126 | /* |
| 127 | * Default values. |
| 128 | */ |
| 129 | #define DNS_DEFAULT_IDLEIN 3600 /*%< 1 hour */ |
| 130 | #define DNS_DEFAULT_IDLEOUT 3600 /*%< 1 hour */ |
| 131 | #define MAX_XFER_TIME (2*3600) /*%< Documented default is 2 hours */ |
| 132 | #define RESIGN_DELAY 3600 /*%< 1 hour */ |
| 133 | |
| 134 | #ifndef DNS_MAX_EXPIRE |
| 135 | #define DNS_MAX_EXPIRE 14515200 /*%< 24 weeks */ |
| 136 | #endif |
| 137 | |
| 138 | #ifndef DNS_DUMP_DELAY |
| 139 | #define DNS_DUMP_DELAY 900 /*%< 15 minutes */ |
| 140 | #endif |
| 141 | |
| 142 | typedef struct dns_notify dns_notify_t; |
| 143 | typedef struct dns_stub dns_stub_t; |
| 144 | typedef struct dns_load dns_load_t; |
| 145 | typedef struct dns_forward dns_forward_t; |
| 146 | typedef ISC_LIST(dns_forward_t) dns_forwardlist_t; |
| 147 | typedef struct dns_io dns_io_t; |
| 148 | typedef ISC_LIST(dns_io_t) dns_iolist_t; |
| 149 | typedef struct dns_signing dns_signing_t; |
| 150 | typedef ISC_LIST(dns_signing_t) dns_signinglist_t; |
| 151 | typedef struct dns_nsec3chain dns_nsec3chain_t; |
| 152 | typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t; |
| 153 | typedef struct dns_keyfetch dns_keyfetch_t; |
| 154 | typedef struct dns_asyncload dns_asyncload_t; |
| 155 | typedef struct dns_include dns_include_t; |
| 156 | |
| 157 | #define DNS_ZONE_CHECKLOCK |
| 158 | #ifdef DNS_ZONE_CHECKLOCK |
| 159 | #define LOCK_ZONE(z) \ |
| 160 | do { LOCK(&(z)->lock); \ |
| 161 | INSIST((z)->locked == false); \ |
| 162 | (z)->locked = true; \ |
| 163 | } while (/*CONSTCOND*/0) |
| 164 | #define UNLOCK_ZONE(z) \ |
| 165 | do { (z)->locked = false; UNLOCK(&(z)->lock); } while (/*CONSTCON*/0) |
| 166 | #define LOCKED_ZONE(z) ((z)->locked) |
| 167 | #define TRYLOCK_ZONE(result, z) \ |
| 168 | do { \ |
| 169 | result = isc_mutex_trylock(&(z)->lock); \ |
| 170 | if (result == ISC_R_SUCCESS) { \ |
| 171 | INSIST((z)->locked == false); \ |
| 172 | (z)->locked = true; \ |
| 173 | } \ |
| 174 | } while (/*CONSTCOND*/0) |
| 175 | #else |
| 176 | #define LOCK_ZONE(z) LOCK(&(z)->lock) |
| 177 | #define UNLOCK_ZONE(z) UNLOCK(&(z)->lock) |
| 178 | #define LOCKED_ZONE(z) true |
| 179 | #define TRYLOCK_ZONE(result, z) \ |
| 180 | do { result = isc_mutex_trylock(&(z)->lock); } while (/*CONSTCOND*/0) |
| 181 | #endif |
| 182 | |
| 183 | #define ZONEDB_INITLOCK(l) isc_rwlock_init((l), 0, 0) |
| 184 | #define ZONEDB_DESTROYLOCK(l) isc_rwlock_destroy(l) |
| 185 | #define ZONEDB_LOCK(l, t) RWLOCK((l), (t)) |
| 186 | #define ZONEDB_UNLOCK(l, t) RWUNLOCK((l), (t)) |
| 187 | |
| 188 | #ifdef ENABLE_AFL |
| 189 | extern bool dns_fuzzing_resolver; |
| 190 | #endif |
| 191 | |
| 192 | struct dns_zone { |
| 193 | /* Unlocked */ |
| 194 | unsigned int magic; |
| 195 | isc_mutex_t lock; |
| 196 | #ifdef DNS_ZONE_CHECKLOCK |
| 197 | bool locked; |
| 198 | #endif |
| 199 | isc_mem_t *mctx; |
| 200 | isc_refcount_t erefs; |
| 201 | |
| 202 | isc_rwlock_t dblock; |
| 203 | dns_db_t *db; /* Locked by dblock */ |
| 204 | |
| 205 | /* Locked */ |
| 206 | dns_zonemgr_t *zmgr; |
| 207 | ISC_LINK(dns_zone_t) link; /* Used by zmgr. */ |
| 208 | isc_timer_t *timer; |
| 209 | unsigned int irefs; |
| 210 | dns_name_t origin; |
| 211 | char *masterfile; |
| 212 | ISC_LIST(dns_include_t) includes; /* Include files */ |
| 213 | ISC_LIST(dns_include_t) newincludes; /* Loading */ |
| 214 | unsigned int nincludes; |
| 215 | dns_masterformat_t masterformat; |
| 216 | const dns_master_style_t *masterstyle; |
| 217 | char *journal; |
| 218 | int32_t journalsize; |
| 219 | dns_rdataclass_t rdclass; |
| 220 | dns_zonetype_t type; |
| 221 | unsigned int flags; |
| 222 | dns_zoneopt_t options; |
| 223 | unsigned int db_argc; |
| 224 | char **db_argv; |
| 225 | isc_time_t expiretime; |
| 226 | isc_time_t refreshtime; |
| 227 | isc_time_t dumptime; |
| 228 | isc_time_t loadtime; |
| 229 | isc_time_t notifytime; |
| 230 | isc_time_t resigntime; |
| 231 | isc_time_t keywarntime; |
| 232 | isc_time_t signingtime; |
| 233 | isc_time_t nsec3chaintime; |
| 234 | isc_time_t refreshkeytime; |
| 235 | uint32_t refreshkeyinterval; |
| 236 | uint32_t refreshkeycount; |
| 237 | uint32_t refresh; |
| 238 | uint32_t retry; |
| 239 | uint32_t expire; |
| 240 | uint32_t minimum; |
| 241 | isc_stdtime_t key_expiry; |
| 242 | isc_stdtime_t log_key_expired_timer; |
| 243 | char *keydirectory; |
| 244 | |
| 245 | uint32_t maxrefresh; |
| 246 | uint32_t minrefresh; |
| 247 | uint32_t maxretry; |
| 248 | uint32_t minretry; |
| 249 | |
| 250 | uint32_t maxrecords; |
| 251 | |
| 252 | isc_sockaddr_t *masters; |
| 253 | isc_dscp_t *masterdscps; |
| 254 | dns_name_t **masterkeynames; |
| 255 | bool *mastersok; |
| 256 | unsigned int masterscnt; |
| 257 | unsigned int curmaster; |
| 258 | isc_sockaddr_t masteraddr; |
| 259 | dns_notifytype_t notifytype; |
| 260 | isc_sockaddr_t *notify; |
| 261 | dns_name_t **notifykeynames; |
| 262 | isc_dscp_t *notifydscp; |
| 263 | unsigned int notifycnt; |
| 264 | isc_sockaddr_t notifyfrom; |
| 265 | isc_task_t *task; |
| 266 | isc_task_t *loadtask; |
| 267 | isc_sockaddr_t notifysrc4; |
| 268 | isc_sockaddr_t notifysrc6; |
| 269 | isc_sockaddr_t xfrsource4; |
| 270 | isc_sockaddr_t xfrsource6; |
| 271 | isc_sockaddr_t altxfrsource4; |
| 272 | isc_sockaddr_t altxfrsource6; |
| 273 | isc_sockaddr_t sourceaddr; |
| 274 | isc_dscp_t notifysrc4dscp; |
| 275 | isc_dscp_t notifysrc6dscp; |
| 276 | isc_dscp_t xfrsource4dscp; |
| 277 | isc_dscp_t xfrsource6dscp; |
| 278 | isc_dscp_t altxfrsource4dscp; |
| 279 | isc_dscp_t altxfrsource6dscp; |
| 280 | dns_xfrin_ctx_t *xfr; /* task locked */ |
| 281 | dns_tsigkey_t *tsigkey; /* key used for xfr */ |
| 282 | /* Access Control Lists */ |
| 283 | dns_acl_t *update_acl; |
| 284 | dns_acl_t *forward_acl; |
| 285 | dns_acl_t *notify_acl; |
| 286 | dns_acl_t *query_acl; |
| 287 | dns_acl_t *queryon_acl; |
| 288 | dns_acl_t *xfr_acl; |
| 289 | bool update_disabled; |
| 290 | bool zero_no_soa_ttl; |
| 291 | dns_severity_t check_names; |
| 292 | ISC_LIST(dns_notify_t) notifies; |
| 293 | dns_request_t *request; |
| 294 | dns_loadctx_t *lctx; |
| 295 | dns_io_t *readio; |
| 296 | dns_dumpctx_t *dctx; |
| 297 | dns_io_t *writeio; |
| 298 | uint32_t maxxfrin; |
| 299 | uint32_t maxxfrout; |
| 300 | uint32_t idlein; |
| 301 | uint32_t idleout; |
| 302 | isc_event_t ctlevent; |
| 303 | dns_ssutable_t *ssutable; |
| 304 | uint32_t sigvalidityinterval; |
| 305 | uint32_t keyvalidityinterval; |
| 306 | uint32_t sigresigninginterval; |
| 307 | dns_view_t *view; |
| 308 | dns_view_t *prev_view; |
| 309 | dns_checkmxfunc_t checkmx; |
| 310 | dns_checksrvfunc_t checksrv; |
| 311 | dns_checknsfunc_t checkns; |
| 312 | /*% |
| 313 | * Zones in certain states such as "waiting for zone transfer" |
| 314 | * or "zone transfer in progress" are kept on per-state linked lists |
| 315 | * in the zone manager using the 'statelink' field. The 'statelist' |
| 316 | * field points at the list the zone is currently on. It the zone |
| 317 | * is not on any such list, statelist is NULL. |
| 318 | */ |
| 319 | ISC_LINK(dns_zone_t) statelink; |
| 320 | dns_zonelist_t *statelist; |
| 321 | /*% |
| 322 | * Statistics counters about zone management. |
| 323 | */ |
| 324 | isc_stats_t *stats; |
| 325 | /*% |
| 326 | * Optional per-zone statistics counters. Counted outside of this |
| 327 | * module. |
| 328 | */ |
| 329 | dns_zonestat_level_t statlevel; |
| 330 | bool requeststats_on; |
| 331 | isc_stats_t *requeststats; |
| 332 | dns_stats_t *rcvquerystats; |
| 333 | uint32_t notifydelay; |
| 334 | dns_isselffunc_t isself; |
| 335 | void *isselfarg; |
| 336 | |
| 337 | char * strnamerd; |
| 338 | char * strname; |
| 339 | char * strrdclass; |
| 340 | char * strviewname; |
| 341 | |
| 342 | /*% |
| 343 | * Serial number for deferred journal compaction. |
| 344 | */ |
| 345 | uint32_t compact_serial; |
| 346 | /*% |
| 347 | * Keys that are signing the zone for the first time. |
| 348 | */ |
| 349 | dns_signinglist_t signing; |
| 350 | dns_nsec3chainlist_t nsec3chain; |
| 351 | /*% |
| 352 | * List of outstanding NSEC3PARAM change requests. |
| 353 | */ |
| 354 | isc_eventlist_t setnsec3param_queue; |
| 355 | /*% |
| 356 | * Signing / re-signing quantum stopping parameters. |
| 357 | */ |
| 358 | uint32_t signatures; |
| 359 | uint32_t nodes; |
| 360 | dns_rdatatype_t privatetype; |
| 361 | |
| 362 | /*% |
| 363 | * Autosigning/key-maintenance options |
| 364 | */ |
| 365 | uint32_t keyopts; |
| 366 | |
| 367 | /*% |
| 368 | * True if added by "rndc addzone" |
| 369 | */ |
| 370 | bool added; |
| 371 | |
| 372 | /*% |
| 373 | * True if added by automatically by named. |
| 374 | */ |
| 375 | bool automatic; |
| 376 | |
| 377 | /*% |
| 378 | * response policy data to be relayed to the database |
| 379 | */ |
| 380 | dns_rpz_zones_t *rpzs; |
| 381 | dns_rpz_num_t rpz_num; |
| 382 | |
| 383 | /*% |
| 384 | * catalog zone data |
| 385 | */ |
| 386 | dns_catz_zones_t *catzs; |
| 387 | |
| 388 | /*% |
| 389 | * parent catalog zone |
| 390 | */ |
| 391 | dns_catz_zone_t *parentcatz; |
| 392 | |
| 393 | /*% |
| 394 | * Serial number update method. |
| 395 | */ |
| 396 | dns_updatemethod_t updatemethod; |
| 397 | |
| 398 | /*% |
| 399 | * whether ixfr is requested |
| 400 | */ |
| 401 | bool requestixfr; |
| 402 | |
| 403 | /*% |
| 404 | * whether EDNS EXPIRE is requested |
| 405 | */ |
| 406 | bool requestexpire; |
| 407 | |
| 408 | /*% |
| 409 | * Outstanding forwarded UPDATE requests. |
| 410 | */ |
| 411 | dns_forwardlist_t forwards; |
| 412 | |
| 413 | dns_zone_t *raw; |
| 414 | dns_zone_t *secure; |
| 415 | |
| 416 | bool sourceserialset; |
| 417 | uint32_t sourceserial; |
| 418 | |
| 419 | /*% |
| 420 | * maximum zone ttl |
| 421 | */ |
| 422 | dns_ttl_t maxttl; |
| 423 | |
| 424 | /* |
| 425 | * Inline zone signing state. |
| 426 | */ |
| 427 | dns_diff_t ; |
| 428 | isc_eventlist_t ; |
| 429 | dns_dbversion_t *; |
| 430 | dns_dbversion_t *; |
| 431 | dns_db_t *; |
| 432 | dns_zone_t *; |
| 433 | isc_event_t *; |
| 434 | dns_update_state_t *; |
| 435 | |
| 436 | isc_stats_t *gluecachestats; |
| 437 | }; |
| 438 | |
| 439 | #define zonediff_init(z, d) \ |
| 440 | do { \ |
| 441 | dns__zonediff_t *_z = (z); \ |
| 442 | (_z)->diff = (d); \ |
| 443 | (_z)->offline = false; \ |
| 444 | } while (/*CONSTCOND*/0) |
| 445 | |
| 446 | #define DNS_ZONE_FLAG(z,f) ((z)->flags & (f)) |
| 447 | #define DNS_ZONE_SETFLAG(z,f) do { \ |
| 448 | INSIST(LOCKED_ZONE(z)); \ |
| 449 | (z)->flags |= (f); \ |
| 450 | } while (/*CONSTCOND*/0) |
| 451 | #define DNS_ZONE_CLRFLAG(z,f) do { \ |
| 452 | INSIST(LOCKED_ZONE(z)); \ |
| 453 | (z)->flags &= ~(f); \ |
| 454 | } while (/*CONSTCOND*/0) |
| 455 | /* XXX MPA these may need to go back into zone.h */ |
| 456 | #define DNS_ZONEFLG_REFRESH 0x00000001U /*%< refresh check in progress */ |
| 457 | #define DNS_ZONEFLG_NEEDDUMP 0x00000002U /*%< zone need consolidation */ |
| 458 | #define DNS_ZONEFLG_USEVC 0x00000004U /*%< use tcp for refresh query */ |
| 459 | #define DNS_ZONEFLG_DUMPING 0x00000008U /*%< a dump is in progress */ |
| 460 | #define DNS_ZONEFLG_HASINCLUDE 0x00000010U /*%< $INCLUDE in zone file */ |
| 461 | #define DNS_ZONEFLG_LOADED 0x00000020U /*%< database has loaded */ |
| 462 | #define DNS_ZONEFLG_EXITING 0x00000040U /*%< zone is being destroyed */ |
| 463 | #define DNS_ZONEFLG_EXPIRED 0x00000080U /*%< zone has expired */ |
| 464 | #define DNS_ZONEFLG_NEEDREFRESH 0x00000100U /*%< refresh check needed */ |
| 465 | #define DNS_ZONEFLG_UPTODATE 0x00000200U /*%< zone contents are |
| 466 | * uptodate */ |
| 467 | #define DNS_ZONEFLG_NEEDNOTIFY 0x00000400U /*%< need to send out notify |
| 468 | * messages */ |
| 469 | #define DNS_ZONEFLG_DIFFONRELOAD 0x00000800U /*%< generate a journal diff on |
| 470 | * reload */ |
| 471 | #define DNS_ZONEFLG_NOMASTERS 0x00001000U /*%< an attempt to refresh a |
| 472 | * zone with no masters |
| 473 | * occurred */ |
| 474 | #define DNS_ZONEFLG_LOADING 0x00002000U /*%< load from disk in progress*/ |
| 475 | #define DNS_ZONEFLG_HAVETIMERS 0x00004000U /*%< timer values have been set |
| 476 | * from SOA (if not set, we |
| 477 | * are still using |
| 478 | * default timer values) */ |
| 479 | #define DNS_ZONEFLG_FORCEXFER 0x00008000U /*%< Force a zone xfer */ |
| 480 | #define DNS_ZONEFLG_NOREFRESH 0x00010000U |
| 481 | #define DNS_ZONEFLG_DIALNOTIFY 0x00020000U |
| 482 | #define DNS_ZONEFLG_DIALREFRESH 0x00040000U |
| 483 | #define DNS_ZONEFLG_SHUTDOWN 0x00080000U |
| 484 | #define DNS_ZONEFLAG_NOIXFR 0x00100000U /*%< IXFR failed, force AXFR */ |
| 485 | #define DNS_ZONEFLG_FLUSH 0x00200000U |
| 486 | #define DNS_ZONEFLG_NOEDNS 0x00400000U |
| 487 | #define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U |
| 488 | #define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U |
| 489 | #define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U |
| 490 | #define DNS_ZONEFLG_REFRESHING 0x04000000U /*%< Refreshing keydata */ |
| 491 | #define DNS_ZONEFLG_THAW 0x08000000U |
| 492 | #define DNS_ZONEFLG_LOADPENDING 0x10000000U /*%< Loading scheduled */ |
| 493 | #define DNS_ZONEFLG_NODELAY 0x20000000U |
| 494 | #define DNS_ZONEFLG_SENDSECURE 0x40000000U |
| 495 | #define DNS_ZONEFLG_NEEDSTARTUPNOTIFY 0x80000000U /*%< need to send out notify |
| 496 | * due to the zone just |
| 497 | * being loaded for the |
| 498 | * first time. */ |
| 499 | |
| 500 | #define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0) |
| 501 | #define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0) |
| 502 | |
| 503 | /* Flags for zone_load() */ |
| 504 | #define DNS_ZONELOADFLAG_NOSTAT 0x00000001U /* Do not stat() master files */ |
| 505 | #define DNS_ZONELOADFLAG_THAW 0x00000002U /* Thaw the zone on successful |
| 506 | load. */ |
| 507 | |
| 508 | #define UNREACH_CHACHE_SIZE 10U |
| 509 | #define UNREACH_HOLD_TIME 600 /* 10 minutes */ |
| 510 | |
| 511 | #define CHECK(op) \ |
| 512 | do { result = (op); \ |
| 513 | if (result != ISC_R_SUCCESS) goto failure; \ |
| 514 | } while (/*CONSTCOND*/0) |
| 515 | |
| 516 | struct dns_unreachable { |
| 517 | isc_sockaddr_t remote; |
| 518 | isc_sockaddr_t local; |
| 519 | uint32_t expire; |
| 520 | uint32_t last; |
| 521 | uint32_t count; |
| 522 | }; |
| 523 | |
| 524 | struct dns_zonemgr { |
| 525 | unsigned int magic; |
| 526 | isc_mem_t * mctx; |
| 527 | int refs; /* Locked by rwlock */ |
| 528 | isc_taskmgr_t * taskmgr; |
| 529 | isc_timermgr_t * timermgr; |
| 530 | isc_socketmgr_t * socketmgr; |
| 531 | isc_taskpool_t * zonetasks; |
| 532 | isc_taskpool_t * loadtasks; |
| 533 | isc_task_t * task; |
| 534 | isc_pool_t * mctxpool; |
| 535 | isc_ratelimiter_t * notifyrl; |
| 536 | isc_ratelimiter_t * refreshrl; |
| 537 | isc_ratelimiter_t * startupnotifyrl; |
| 538 | isc_ratelimiter_t * startuprefreshrl; |
| 539 | isc_rwlock_t rwlock; |
| 540 | isc_mutex_t iolock; |
| 541 | isc_rwlock_t urlock; |
| 542 | |
| 543 | /* Locked by rwlock. */ |
| 544 | dns_zonelist_t zones; |
| 545 | dns_zonelist_t waiting_for_xfrin; |
| 546 | dns_zonelist_t xfrin_in_progress; |
| 547 | |
| 548 | /* Configuration data. */ |
| 549 | uint32_t transfersin; |
| 550 | uint32_t transfersperns; |
| 551 | unsigned int notifyrate; |
| 552 | unsigned int startupnotifyrate; |
| 553 | unsigned int serialqueryrate; |
| 554 | unsigned int startupserialqueryrate; |
| 555 | |
| 556 | /* Locked by iolock */ |
| 557 | uint32_t iolimit; |
| 558 | uint32_t ioactive; |
| 559 | dns_iolist_t high; |
| 560 | dns_iolist_t low; |
| 561 | |
| 562 | /* Locked by urlock. */ |
| 563 | /* LRU cache */ |
| 564 | struct dns_unreachable unreachable[UNREACH_CHACHE_SIZE]; |
| 565 | }; |
| 566 | |
| 567 | /*% |
| 568 | * Hold notify state. |
| 569 | */ |
| 570 | struct dns_notify { |
| 571 | unsigned int magic; |
| 572 | unsigned int flags; |
| 573 | isc_mem_t *mctx; |
| 574 | dns_zone_t *zone; |
| 575 | dns_adbfind_t *find; |
| 576 | dns_request_t *request; |
| 577 | dns_name_t ns; |
| 578 | isc_sockaddr_t dst; |
| 579 | dns_tsigkey_t *key; |
| 580 | isc_dscp_t dscp; |
| 581 | ISC_LINK(dns_notify_t) link; |
| 582 | isc_event_t *event; |
| 583 | }; |
| 584 | |
| 585 | #define DNS_NOTIFY_NOSOA 0x0001U |
| 586 | #define DNS_NOTIFY_STARTUP 0x0002U |
| 587 | |
| 588 | /*% |
| 589 | * dns_stub holds state while performing a 'stub' transfer. |
| 590 | * 'db' is the zone's 'db' or a new one if this is the initial |
| 591 | * transfer. |
| 592 | */ |
| 593 | |
| 594 | struct dns_stub { |
| 595 | unsigned int magic; |
| 596 | isc_mem_t *mctx; |
| 597 | dns_zone_t *zone; |
| 598 | dns_db_t *db; |
| 599 | dns_dbversion_t *version; |
| 600 | }; |
| 601 | |
| 602 | /*% |
| 603 | * Hold load state. |
| 604 | */ |
| 605 | struct dns_load { |
| 606 | unsigned int magic; |
| 607 | isc_mem_t *mctx; |
| 608 | dns_zone_t *zone; |
| 609 | dns_db_t *db; |
| 610 | isc_time_t loadtime; |
| 611 | dns_rdatacallbacks_t callbacks; |
| 612 | }; |
| 613 | |
| 614 | /*% |
| 615 | * Hold forward state. |
| 616 | */ |
| 617 | struct dns_forward { |
| 618 | unsigned int magic; |
| 619 | isc_mem_t *mctx; |
| 620 | dns_zone_t *zone; |
| 621 | isc_buffer_t *msgbuf; |
| 622 | dns_request_t *request; |
| 623 | uint32_t which; |
| 624 | isc_sockaddr_t addr; |
| 625 | dns_updatecallback_t callback; |
| 626 | void *callback_arg; |
| 627 | unsigned int options; |
| 628 | ISC_LINK(dns_forward_t) link; |
| 629 | }; |
| 630 | |
| 631 | /*% |
| 632 | * Hold IO request state. |
| 633 | */ |
| 634 | struct dns_io { |
| 635 | unsigned int magic; |
| 636 | dns_zonemgr_t *zmgr; |
| 637 | bool high; |
| 638 | isc_task_t *task; |
| 639 | ISC_LINK(dns_io_t) link; |
| 640 | isc_event_t *event; |
| 641 | }; |
| 642 | |
| 643 | /*% |
| 644 | * Hold state for when we are signing a zone with a new |
| 645 | * DNSKEY as result of an update. |
| 646 | */ |
| 647 | struct dns_signing { |
| 648 | unsigned int magic; |
| 649 | dns_db_t *db; |
| 650 | dns_dbiterator_t *dbiterator; |
| 651 | dns_secalg_t algorithm; |
| 652 | uint16_t keyid; |
| 653 | bool deleteit; |
| 654 | bool done; |
| 655 | ISC_LINK(dns_signing_t) link; |
| 656 | }; |
| 657 | |
| 658 | struct dns_nsec3chain { |
| 659 | unsigned int magic; |
| 660 | dns_db_t *db; |
| 661 | dns_dbiterator_t *dbiterator; |
| 662 | dns_rdata_nsec3param_t nsec3param; |
| 663 | unsigned char salt[255]; |
| 664 | bool done; |
| 665 | bool seen_nsec; |
| 666 | bool delete_nsec; |
| 667 | bool save_delete_nsec; |
| 668 | ISC_LINK(dns_nsec3chain_t) link; |
| 669 | }; |
| 670 | /*%< |
| 671 | * 'dbiterator' contains a iterator for the database. If we are creating |
| 672 | * a NSEC3 chain only the non-NSEC3 nodes will be iterated. If we are |
| 673 | * removing a NSEC3 chain then both NSEC3 and non-NSEC3 nodes will be |
| 674 | * iterated. |
| 675 | * |
| 676 | * 'nsec3param' contains the parameters of the NSEC3 chain being created |
| 677 | * or removed. |
| 678 | * |
| 679 | * 'salt' is buffer space and is referenced via 'nsec3param.salt'. |
| 680 | * |
| 681 | * 'seen_nsec' will be set to true if, while iterating the zone to create a |
| 682 | * NSEC3 chain, a NSEC record is seen. |
| 683 | * |
| 684 | * 'delete_nsec' will be set to true if, at the completion of the creation |
| 685 | * of a NSEC3 chain, 'seen_nsec' is true. If 'delete_nsec' is true then we |
| 686 | * are in the process of deleting the NSEC chain. |
| 687 | * |
| 688 | * 'save_delete_nsec' is used to store the initial state of 'delete_nsec' |
| 689 | * so it can be recovered in the event of a error. |
| 690 | */ |
| 691 | |
| 692 | struct dns_keyfetch { |
| 693 | dns_fixedname_t name; |
| 694 | dns_rdataset_t keydataset; |
| 695 | dns_rdataset_t dnskeyset; |
| 696 | dns_rdataset_t dnskeysigset; |
| 697 | dns_zone_t *zone; |
| 698 | dns_db_t *db; |
| 699 | dns_fetch_t *fetch; |
| 700 | }; |
| 701 | |
| 702 | /*% |
| 703 | * Hold state for an asynchronous load |
| 704 | */ |
| 705 | struct dns_asyncload { |
| 706 | dns_zone_t *zone; |
| 707 | unsigned int flags; |
| 708 | dns_zt_zoneloaded_t loaded; |
| 709 | void *loaded_arg; |
| 710 | }; |
| 711 | |
| 712 | /*% |
| 713 | * Reference to an include file encountered during loading |
| 714 | */ |
| 715 | struct dns_include { |
| 716 | char *name; |
| 717 | isc_time_t filetime; |
| 718 | ISC_LINK(dns_include_t) link; |
| 719 | }; |
| 720 | |
| 721 | /* |
| 722 | * These can be overridden by the -T mkeytimers option on the command |
| 723 | * line, so that we can test with shorter periods than specified in |
| 724 | * RFC 5011. |
| 725 | */ |
| 726 | #define HOUR 3600 |
| 727 | #define DAY (24*HOUR) |
| 728 | #define MONTH (30*DAY) |
| 729 | LIBDNS_EXTERNAL_DATA unsigned int dns_zone_mkey_hour = HOUR; |
| 730 | LIBDNS_EXTERNAL_DATA unsigned int dns_zone_mkey_day = DAY; |
| 731 | LIBDNS_EXTERNAL_DATA unsigned int dns_zone_mkey_month = MONTH; |
| 732 | |
| 733 | #define SEND_BUFFER_SIZE 2048 |
| 734 | |
| 735 | static void zone_settimer(dns_zone_t *, isc_time_t *); |
| 736 | static void cancel_refresh(dns_zone_t *); |
| 737 | static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel, |
| 738 | const char *msg, ...) ISC_FORMAT_PRINTF(4, 5); |
| 739 | static void notify_log(dns_zone_t *zone, int level, const char *fmt, ...) |
| 740 | ISC_FORMAT_PRINTF(3, 4); |
| 741 | static void dnssec_log(dns_zone_t *zone, int level, const char *fmt, ...) |
| 742 | ISC_FORMAT_PRINTF(3, 4); |
| 743 | static void queue_xfrin(dns_zone_t *zone); |
| 744 | static isc_result_t update_one_rr(dns_db_t *db, dns_dbversion_t *ver, |
| 745 | dns_diff_t *diff, dns_diffop_t op, |
| 746 | dns_name_t *name, dns_ttl_t ttl, |
| 747 | dns_rdata_t *rdata); |
| 748 | static void zone_unload(dns_zone_t *zone); |
| 749 | static void zone_expire(dns_zone_t *zone); |
| 750 | static void zone_iattach(dns_zone_t *source, dns_zone_t **target); |
| 751 | static void zone_idetach(dns_zone_t **zonep); |
| 752 | static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db, |
| 753 | bool dump); |
| 754 | static inline void zone_attachdb(dns_zone_t *zone, dns_db_t *db); |
| 755 | static inline void zone_detachdb(dns_zone_t *zone); |
| 756 | static isc_result_t default_journal(dns_zone_t *zone); |
| 757 | static void zone_xfrdone(dns_zone_t *zone, isc_result_t result); |
| 758 | static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db, |
| 759 | isc_time_t loadtime, isc_result_t result); |
| 760 | static void zone_needdump(dns_zone_t *zone, unsigned int delay); |
| 761 | static void zone_shutdown(isc_task_t *, isc_event_t *); |
| 762 | static void zone_loaddone(void *arg, isc_result_t result); |
| 763 | static isc_result_t zone_startload(dns_db_t *db, dns_zone_t *zone, |
| 764 | isc_time_t loadtime); |
| 765 | static void zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length); |
| 766 | static void zone_name_tostr(dns_zone_t *zone, char *buf, size_t length); |
| 767 | static void zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length); |
| 768 | static void zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length); |
| 769 | static isc_result_t zone_send_secureserial(dns_zone_t *zone, |
| 770 | uint32_t serial); |
| 771 | static void refresh_callback(isc_task_t *, isc_event_t *); |
| 772 | static void stub_callback(isc_task_t *, isc_event_t *); |
| 773 | static void queue_soa_query(dns_zone_t *zone); |
| 774 | static void soa_query(isc_task_t *, isc_event_t *); |
| 775 | static void ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, |
| 776 | dns_stub_t *stub); |
| 777 | static int message_count(dns_message_t *msg, dns_section_t section, |
| 778 | dns_rdatatype_t type); |
| 779 | static void notify_cancel(dns_zone_t *zone); |
| 780 | static void notify_find_address(dns_notify_t *notify); |
| 781 | static void notify_send(dns_notify_t *notify); |
| 782 | static isc_result_t notify_createmessage(dns_zone_t *zone, |
| 783 | unsigned int flags, |
| 784 | dns_message_t **messagep); |
| 785 | static void notify_done(isc_task_t *task, isc_event_t *event); |
| 786 | static void notify_send_toaddr(isc_task_t *task, isc_event_t *event); |
| 787 | static isc_result_t zone_dump(dns_zone_t *, bool); |
| 788 | static void got_transfer_quota(isc_task_t *task, isc_event_t *event); |
| 789 | static isc_result_t zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, |
| 790 | dns_zone_t *zone); |
| 791 | static void zmgr_resume_xfrs(dns_zonemgr_t *zmgr, bool multi); |
| 792 | static void zonemgr_free(dns_zonemgr_t *zmgr); |
| 793 | static isc_result_t zonemgr_getio(dns_zonemgr_t *zmgr, bool high, |
| 794 | isc_task_t *task, isc_taskaction_t action, |
| 795 | void *arg, dns_io_t **iop); |
| 796 | static void zonemgr_putio(dns_io_t **iop); |
| 797 | static void zonemgr_cancelio(dns_io_t *io); |
| 798 | |
| 799 | static isc_result_t |
| 800 | zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, |
| 801 | unsigned int *soacount, uint32_t *serial, |
| 802 | uint32_t *refresh, uint32_t *retry, |
| 803 | uint32_t *expire, uint32_t *minimum, |
| 804 | unsigned int *errors); |
| 805 | |
| 806 | static void zone_freedbargs(dns_zone_t *zone); |
| 807 | static void forward_callback(isc_task_t *task, isc_event_t *event); |
| 808 | static void zone_saveunique(dns_zone_t *zone, const char *path, |
| 809 | const char *templat); |
| 810 | static void zone_maintenance(dns_zone_t *zone); |
| 811 | static void zone_notify(dns_zone_t *zone, isc_time_t *now); |
| 812 | static void dump_done(void *arg, isc_result_t result); |
| 813 | static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, |
| 814 | uint16_t keyid, |
| 815 | bool deleteit); |
| 816 | static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver, |
| 817 | dns_dbnode_t *node, dns_name_t *name, |
| 818 | dns_diff_t *diff); |
| 819 | static void zone_rekey(dns_zone_t *zone); |
| 820 | static isc_result_t zone_send_securedb(dns_zone_t *zone, dns_db_t *db); |
| 821 | static void setrl(isc_ratelimiter_t *rl, unsigned int *rate, |
| 822 | unsigned int value); |
| 823 | |
| 824 | #define ENTER zone_debuglog(zone, me, 1, "enter") |
| 825 | |
| 826 | static const unsigned int dbargc_default = 1; |
| 827 | static const char *dbargv_default[] = { "rbt" }; |
| 828 | |
| 829 | #define DNS_ZONE_JITTER_ADD(a, b, c) \ |
| 830 | do { \ |
| 831 | isc_interval_t _i; \ |
| 832 | uint32_t _j; \ |
| 833 | _j = (b) - isc_random_uniform((b)/4); \ |
| 834 | isc_interval_set(&_i, _j, 0); \ |
| 835 | if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \ |
| 836 | dns_zone_log(zone, ISC_LOG_WARNING, \ |
| 837 | "epoch approaching: upgrade required: " \ |
| 838 | "now + %s failed", #b); \ |
| 839 | isc_interval_set(&_i, _j/2, 0); \ |
| 840 | (void)isc_time_add((a), &_i, (c)); \ |
| 841 | } \ |
| 842 | } while (/*CONSTCOND*/0) |
| 843 | |
| 844 | #define DNS_ZONE_TIME_ADD(a, b, c) \ |
| 845 | do { \ |
| 846 | isc_interval_t _i; \ |
| 847 | isc_interval_set(&_i, (b), 0); \ |
| 848 | if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \ |
| 849 | dns_zone_log(zone, ISC_LOG_WARNING, \ |
| 850 | "epoch approaching: upgrade required: " \ |
| 851 | "now + %s failed", #b); \ |
| 852 | isc_interval_set(&_i, (b)/2, 0); \ |
| 853 | (void)isc_time_add((a), &_i, (c)); \ |
| 854 | } \ |
| 855 | } while (/*CONSTCOND*/0) |
| 856 | |
| 857 | typedef struct nsec3param nsec3param_t; |
| 858 | struct nsec3param { |
| 859 | unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1]; |
| 860 | unsigned int length; |
| 861 | bool nsec; |
| 862 | bool replace; |
| 863 | ISC_LINK(nsec3param_t) link; |
| 864 | }; |
| 865 | typedef ISC_LIST(nsec3param_t) nsec3paramlist_t; |
| 866 | struct np3event { |
| 867 | isc_event_t event; |
| 868 | nsec3param_t params; |
| 869 | }; |
| 870 | |
| 871 | struct ssevent { |
| 872 | isc_event_t event; |
| 873 | uint32_t serial; |
| 874 | }; |
| 875 | |
| 876 | /*% |
| 877 | * Increment resolver-related statistics counters. Zone must be locked. |
| 878 | */ |
| 879 | static inline void |
| 880 | inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { |
| 881 | if (zone->stats != NULL) |
| 882 | isc_stats_increment(zone->stats, counter); |
| 883 | } |
| 884 | |
| 885 | /*** |
| 886 | *** Public functions. |
| 887 | ***/ |
| 888 | |
| 889 | isc_result_t |
| 890 | dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { |
| 891 | isc_result_t result; |
| 892 | dns_zone_t *zone; |
| 893 | isc_time_t now; |
| 894 | |
| 895 | REQUIRE(zonep != NULL && *zonep == NULL); |
| 896 | REQUIRE(mctx != NULL); |
| 897 | |
| 898 | TIME_NOW(&now); |
| 899 | zone = isc_mem_get(mctx, sizeof(*zone)); |
| 900 | if (zone == NULL) { |
| 901 | return (ISC_R_NOMEMORY); |
| 902 | } |
| 903 | |
| 904 | zone->mctx = NULL; |
| 905 | isc_mem_attach(mctx, &zone->mctx); |
| 906 | |
| 907 | isc_mutex_init(&zone->lock); |
| 908 | |
| 909 | result = ZONEDB_INITLOCK(&zone->dblock); |
| 910 | if (result != ISC_R_SUCCESS) { |
| 911 | goto free_mutex; |
| 912 | } |
| 913 | |
| 914 | /* XXX MPA check that all elements are initialised */ |
| 915 | #ifdef DNS_ZONE_CHECKLOCK |
| 916 | zone->locked = false; |
| 917 | #endif |
| 918 | zone->db = NULL; |
| 919 | zone->zmgr = NULL; |
| 920 | ISC_LINK_INIT(zone, link); |
| 921 | isc_refcount_init(&zone->erefs, 1); /* Implicit attach. */ |
| 922 | zone->irefs = 0; |
| 923 | dns_name_init(&zone->origin, NULL); |
| 924 | zone->strnamerd = NULL; |
| 925 | zone->strname = NULL; |
| 926 | zone->strrdclass = NULL; |
| 927 | zone->strviewname = NULL; |
| 928 | zone->masterfile = NULL; |
| 929 | ISC_LIST_INIT(zone->includes); |
| 930 | ISC_LIST_INIT(zone->newincludes); |
| 931 | zone->nincludes = 0; |
| 932 | zone->masterformat = dns_masterformat_none; |
| 933 | zone->masterstyle = NULL; |
| 934 | zone->keydirectory = NULL; |
| 935 | zone->journalsize = -1; |
| 936 | zone->journal = NULL; |
| 937 | zone->rdclass = dns_rdataclass_none; |
| 938 | zone->type = dns_zone_none; |
| 939 | zone->flags = 0; |
| 940 | zone->options = 0; |
| 941 | zone->keyopts = 0; |
| 942 | zone->db_argc = 0; |
| 943 | zone->db_argv = NULL; |
| 944 | isc_time_settoepoch(&zone->expiretime); |
| 945 | isc_time_settoepoch(&zone->refreshtime); |
| 946 | isc_time_settoepoch(&zone->dumptime); |
| 947 | isc_time_settoepoch(&zone->loadtime); |
| 948 | zone->notifytime = now; |
| 949 | isc_time_settoepoch(&zone->resigntime); |
| 950 | isc_time_settoepoch(&zone->keywarntime); |
| 951 | isc_time_settoepoch(&zone->signingtime); |
| 952 | isc_time_settoepoch(&zone->nsec3chaintime); |
| 953 | isc_time_settoepoch(&zone->refreshkeytime); |
| 954 | zone->refreshkeyinterval = 0; |
| 955 | zone->refreshkeycount = 0; |
| 956 | zone->refresh = DNS_ZONE_DEFAULTREFRESH; |
| 957 | zone->retry = DNS_ZONE_DEFAULTRETRY; |
| 958 | zone->expire = 0; |
| 959 | zone->minimum = 0; |
| 960 | zone->maxrefresh = DNS_ZONE_MAXREFRESH; |
| 961 | zone->minrefresh = DNS_ZONE_MINREFRESH; |
| 962 | zone->maxretry = DNS_ZONE_MAXRETRY; |
| 963 | zone->minretry = DNS_ZONE_MINRETRY; |
| 964 | zone->masters = NULL; |
| 965 | zone->masterdscps = NULL; |
| 966 | zone->masterkeynames = NULL; |
| 967 | zone->mastersok = NULL; |
| 968 | zone->masterscnt = 0; |
| 969 | zone->curmaster = 0; |
| 970 | zone->maxttl = 0; |
| 971 | zone->notify = NULL; |
| 972 | zone->notifykeynames = NULL; |
| 973 | zone->notifydscp = NULL; |
| 974 | zone->notifytype = dns_notifytype_yes; |
| 975 | zone->notifycnt = 0; |
| 976 | zone->task = NULL; |
| 977 | zone->loadtask = NULL; |
| 978 | zone->update_acl = NULL; |
| 979 | zone->forward_acl = NULL; |
| 980 | zone->notify_acl = NULL; |
| 981 | zone->query_acl = NULL; |
| 982 | zone->queryon_acl = NULL; |
| 983 | zone->xfr_acl = NULL; |
| 984 | zone->update_disabled = false; |
| 985 | zone->zero_no_soa_ttl = true; |
| 986 | zone->check_names = dns_severity_ignore; |
| 987 | zone->request = NULL; |
| 988 | zone->lctx = NULL; |
| 989 | zone->readio = NULL; |
| 990 | zone->dctx = NULL; |
| 991 | zone->writeio = NULL; |
| 992 | zone->timer = NULL; |
| 993 | zone->idlein = DNS_DEFAULT_IDLEIN; |
| 994 | zone->idleout = DNS_DEFAULT_IDLEOUT; |
| 995 | zone->log_key_expired_timer = 0; |
| 996 | ISC_LIST_INIT(zone->notifies); |
| 997 | isc_sockaddr_any(&zone->notifysrc4); |
| 998 | isc_sockaddr_any6(&zone->notifysrc6); |
| 999 | isc_sockaddr_any(&zone->xfrsource4); |
| 1000 | isc_sockaddr_any6(&zone->xfrsource6); |
| 1001 | isc_sockaddr_any(&zone->altxfrsource4); |
| 1002 | isc_sockaddr_any6(&zone->altxfrsource6); |
| 1003 | zone->notifysrc4dscp = -1; |
| 1004 | zone->notifysrc6dscp = -1; |
| 1005 | zone->xfrsource4dscp = -1; |
| 1006 | zone->xfrsource6dscp = -1; |
| 1007 | zone->altxfrsource4dscp = -1; |
| 1008 | zone->altxfrsource6dscp = -1; |
| 1009 | zone->xfr = NULL; |
| 1010 | zone->tsigkey = NULL; |
| 1011 | zone->maxxfrin = MAX_XFER_TIME; |
| 1012 | zone->maxxfrout = MAX_XFER_TIME; |
| 1013 | zone->ssutable = NULL; |
| 1014 | zone->sigvalidityinterval = 30 * 24 * 3600; |
| 1015 | zone->keyvalidityinterval = 0; |
| 1016 | zone->sigresigninginterval = 7 * 24 * 3600; |
| 1017 | zone->view = NULL; |
| 1018 | zone->prev_view = NULL; |
| 1019 | zone->checkmx = NULL; |
| 1020 | zone->checksrv = NULL; |
| 1021 | zone->checkns = NULL; |
| 1022 | ISC_LINK_INIT(zone, statelink); |
| 1023 | zone->statelist = NULL; |
| 1024 | zone->stats = NULL; |
| 1025 | zone->requeststats_on = false; |
| 1026 | zone->statlevel = dns_zonestat_none; |
| 1027 | zone->requeststats = NULL; |
| 1028 | zone->rcvquerystats = NULL; |
| 1029 | zone->notifydelay = 5; |
| 1030 | zone->isself = NULL; |
| 1031 | zone->isselfarg = NULL; |
| 1032 | ISC_LIST_INIT(zone->signing); |
| 1033 | ISC_LIST_INIT(zone->nsec3chain); |
| 1034 | ISC_LIST_INIT(zone->setnsec3param_queue); |
| 1035 | zone->signatures = 10; |
| 1036 | zone->nodes = 100; |
| 1037 | zone->privatetype = (dns_rdatatype_t)0xffffU; |
| 1038 | zone->added = false; |
| 1039 | zone->automatic = false; |
| 1040 | zone->rpzs = NULL; |
| 1041 | zone->rpz_num = DNS_RPZ_INVALID_NUM; |
| 1042 | |
| 1043 | zone->catzs = NULL; |
| 1044 | zone->parentcatz = NULL; |
| 1045 | |
| 1046 | ISC_LIST_INIT(zone->forwards); |
| 1047 | zone->raw = NULL; |
| 1048 | zone->secure = NULL; |
| 1049 | zone->sourceserial = 0; |
| 1050 | zone->sourceserialset = false; |
| 1051 | zone->requestixfr = true; |
| 1052 | zone->requestexpire = true; |
| 1053 | ISC_LIST_INIT(zone->rss_events); |
| 1054 | zone->rss_db = NULL; |
| 1055 | zone->rss_raw = NULL; |
| 1056 | zone->rss_newver = NULL; |
| 1057 | zone->rss_oldver = NULL; |
| 1058 | zone->rss_event = NULL; |
| 1059 | zone->rss_state = NULL; |
| 1060 | zone->updatemethod = dns_updatemethod_increment; |
| 1061 | zone->maxrecords = 0U; |
| 1062 | |
| 1063 | zone->magic = ZONE_MAGIC; |
| 1064 | |
| 1065 | zone->gluecachestats = NULL; |
| 1066 | result = isc_stats_create(mctx, &zone->gluecachestats, |
| 1067 | dns_gluecachestatscounter_max); |
| 1068 | if (result != ISC_R_SUCCESS) { |
| 1069 | goto free_erefs; |
| 1070 | } |
| 1071 | |
| 1072 | /* Must be after magic is set. */ |
| 1073 | result = dns_zone_setdbtype(zone, dbargc_default, dbargv_default); |
| 1074 | if (result != ISC_R_SUCCESS) { |
| 1075 | goto free_stats; |
| 1076 | } |
| 1077 | |
| 1078 | ISC_EVENT_INIT(&zone->ctlevent, sizeof(zone->ctlevent), 0, NULL, |
| 1079 | DNS_EVENT_ZONECONTROL, zone_shutdown, zone, zone, |
| 1080 | NULL, NULL); |
| 1081 | *zonep = zone; |
| 1082 | return (ISC_R_SUCCESS); |
| 1083 | |
| 1084 | free_stats: |
| 1085 | if (zone->gluecachestats != NULL) |
| 1086 | isc_stats_detach(&zone->gluecachestats); |
| 1087 | |
| 1088 | free_erefs: |
| 1089 | INSIST(isc_refcount_decrement(&zone->erefs) > 0); |
| 1090 | isc_refcount_destroy(&zone->erefs); |
| 1091 | |
| 1092 | ZONEDB_DESTROYLOCK(&zone->dblock); |
| 1093 | |
| 1094 | free_mutex: |
| 1095 | isc_mutex_destroy(&zone->lock); |
| 1096 | |
| 1097 | isc_mem_putanddetach(&zone->mctx, zone, sizeof(*zone)); |
| 1098 | return (result); |
| 1099 | } |
| 1100 | |
| 1101 | /* |
| 1102 | * Free a zone. Because we require that there be no more |
| 1103 | * outstanding events or references, no locking is necessary. |
| 1104 | */ |
| 1105 | static void |
| 1106 | zone_free(dns_zone_t *zone) { |
| 1107 | isc_mem_t *mctx = NULL; |
| 1108 | dns_signing_t *signing; |
| 1109 | dns_nsec3chain_t *nsec3chain; |
| 1110 | isc_event_t *setnsec3param_event; |
| 1111 | dns_include_t *include; |
| 1112 | |
| 1113 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1114 | REQUIRE(isc_refcount_current(&zone->erefs) == 0); |
| 1115 | REQUIRE(zone->irefs == 0); |
| 1116 | REQUIRE(!LOCKED_ZONE(zone)); |
| 1117 | REQUIRE(zone->timer == NULL); |
| 1118 | REQUIRE(zone->zmgr == NULL); |
| 1119 | |
| 1120 | /* |
| 1121 | * Managed objects. Order is important. |
| 1122 | */ |
| 1123 | if (zone->request != NULL) { |
| 1124 | dns_request_destroy(&zone->request); /* XXXMPA */ |
| 1125 | } |
| 1126 | INSIST(zone->readio == NULL); |
| 1127 | INSIST(zone->statelist == NULL); |
| 1128 | INSIST(zone->writeio == NULL); |
| 1129 | |
| 1130 | if (zone->task != NULL) { |
| 1131 | isc_task_detach(&zone->task); |
| 1132 | } |
| 1133 | if (zone->loadtask != NULL) { |
| 1134 | isc_task_detach(&zone->loadtask); |
| 1135 | } |
| 1136 | if (zone->view != NULL) { |
| 1137 | dns_view_weakdetach(&zone->view); |
| 1138 | } |
| 1139 | if (zone->prev_view != NULL) { |
| 1140 | dns_view_weakdetach(&zone->prev_view); |
| 1141 | } |
| 1142 | |
| 1143 | /* Unmanaged objects */ |
| 1144 | while (!ISC_LIST_EMPTY(zone->setnsec3param_queue)) { |
| 1145 | setnsec3param_event = ISC_LIST_HEAD(zone->setnsec3param_queue); |
| 1146 | ISC_LIST_UNLINK(zone->setnsec3param_queue, setnsec3param_event, |
| 1147 | ev_link); |
| 1148 | isc_event_free(&setnsec3param_event); |
| 1149 | } |
| 1150 | for (signing = ISC_LIST_HEAD(zone->signing); |
| 1151 | signing != NULL; |
| 1152 | signing = ISC_LIST_HEAD(zone->signing)) { |
| 1153 | ISC_LIST_UNLINK(zone->signing, signing, link); |
| 1154 | dns_db_detach(&signing->db); |
| 1155 | dns_dbiterator_destroy(&signing->dbiterator); |
| 1156 | isc_mem_put(zone->mctx, signing, sizeof *signing); |
| 1157 | } |
| 1158 | for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); |
| 1159 | nsec3chain != NULL; |
| 1160 | nsec3chain = ISC_LIST_HEAD(zone->nsec3chain)) { |
| 1161 | ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link); |
| 1162 | dns_db_detach(&nsec3chain->db); |
| 1163 | dns_dbiterator_destroy(&nsec3chain->dbiterator); |
| 1164 | isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); |
| 1165 | } |
| 1166 | for (include = ISC_LIST_HEAD(zone->includes); |
| 1167 | include != NULL; |
| 1168 | include = ISC_LIST_HEAD(zone->includes)) { |
| 1169 | ISC_LIST_UNLINK(zone->includes, include, link); |
| 1170 | isc_mem_free(zone->mctx, include->name); |
| 1171 | isc_mem_put(zone->mctx, include, sizeof *include); |
| 1172 | } |
| 1173 | for (include = ISC_LIST_HEAD(zone->newincludes); |
| 1174 | include != NULL; |
| 1175 | include = ISC_LIST_HEAD(zone->newincludes)) { |
| 1176 | ISC_LIST_UNLINK(zone->newincludes, include, link); |
| 1177 | isc_mem_free(zone->mctx, include->name); |
| 1178 | isc_mem_put(zone->mctx, include, sizeof *include); |
| 1179 | } |
| 1180 | if (zone->masterfile != NULL) { |
| 1181 | isc_mem_free(zone->mctx, zone->masterfile); |
| 1182 | } |
| 1183 | zone->masterfile = NULL; |
| 1184 | if (zone->keydirectory != NULL) { |
| 1185 | isc_mem_free(zone->mctx, zone->keydirectory); |
| 1186 | } |
| 1187 | zone->keydirectory = NULL; |
| 1188 | zone->journalsize = -1; |
| 1189 | if (zone->journal != NULL) { |
| 1190 | isc_mem_free(zone->mctx, zone->journal); |
| 1191 | } |
| 1192 | zone->journal = NULL; |
| 1193 | if (zone->stats != NULL) { |
| 1194 | isc_stats_detach(&zone->stats); |
| 1195 | } |
| 1196 | if (zone->requeststats != NULL) { |
| 1197 | isc_stats_detach(&zone->requeststats); |
| 1198 | } |
| 1199 | if (zone->rcvquerystats != NULL){ |
| 1200 | dns_stats_detach(&zone->rcvquerystats); |
| 1201 | } |
| 1202 | if (zone->db != NULL) { |
| 1203 | zone_detachdb(zone); |
| 1204 | } |
| 1205 | if (zone->rpzs != NULL) { |
| 1206 | REQUIRE(zone->rpz_num < zone->rpzs->p.num_zones); |
| 1207 | dns_rpz_detach_rpzs(&zone->rpzs); |
| 1208 | zone->rpz_num = DNS_RPZ_INVALID_NUM; |
| 1209 | } |
| 1210 | if (zone->catzs != NULL) { |
| 1211 | dns_catz_catzs_detach(&zone->catzs); |
| 1212 | } |
| 1213 | zone_freedbargs(zone); |
| 1214 | RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL, |
| 1215 | NULL, 0) == ISC_R_SUCCESS); |
| 1216 | RUNTIME_CHECK(dns_zone_setalsonotify(zone, NULL, 0) == ISC_R_SUCCESS); |
| 1217 | zone->check_names = dns_severity_ignore; |
| 1218 | if (zone->update_acl != NULL) { |
| 1219 | dns_acl_detach(&zone->update_acl); |
| 1220 | } |
| 1221 | if (zone->forward_acl != NULL) { |
| 1222 | dns_acl_detach(&zone->forward_acl); |
| 1223 | } |
| 1224 | if (zone->notify_acl != NULL) { |
| 1225 | dns_acl_detach(&zone->notify_acl); |
| 1226 | } |
| 1227 | if (zone->query_acl != NULL) { |
| 1228 | dns_acl_detach(&zone->query_acl); |
| 1229 | } |
| 1230 | if (zone->queryon_acl != NULL) { |
| 1231 | dns_acl_detach(&zone->queryon_acl); |
| 1232 | } |
| 1233 | if (zone->xfr_acl != NULL) { |
| 1234 | dns_acl_detach(&zone->xfr_acl); |
| 1235 | } |
| 1236 | if (dns_name_dynamic(&zone->origin)) { |
| 1237 | dns_name_free(&zone->origin, zone->mctx); |
| 1238 | } |
| 1239 | if (zone->strnamerd != NULL) { |
| 1240 | isc_mem_free(zone->mctx, zone->strnamerd); |
| 1241 | } |
| 1242 | if (zone->strname != NULL) { |
| 1243 | isc_mem_free(zone->mctx, zone->strname); |
| 1244 | } |
| 1245 | if (zone->strrdclass != NULL) { |
| 1246 | isc_mem_free(zone->mctx, zone->strrdclass); |
| 1247 | } |
| 1248 | if (zone->strviewname != NULL) { |
| 1249 | isc_mem_free(zone->mctx, zone->strviewname); |
| 1250 | } |
| 1251 | if (zone->ssutable != NULL) { |
| 1252 | dns_ssutable_detach(&zone->ssutable); |
| 1253 | } |
| 1254 | if (zone->gluecachestats != NULL) { |
| 1255 | isc_stats_detach(&zone->gluecachestats); |
| 1256 | } |
| 1257 | |
| 1258 | /* last stuff */ |
| 1259 | ZONEDB_DESTROYLOCK(&zone->dblock); |
| 1260 | isc_mutex_destroy(&zone->lock); |
| 1261 | zone->magic = 0; |
| 1262 | mctx = zone->mctx; |
| 1263 | isc_mem_put(mctx, zone, sizeof(*zone)); |
| 1264 | isc_mem_detach(&mctx); |
| 1265 | } |
| 1266 | |
| 1267 | /* |
| 1268 | * Returns true iff this the signed side of an inline-signing zone. |
| 1269 | * Caller should hold zone lock. |
| 1270 | */ |
| 1271 | static inline bool |
| 1272 | inline_secure(dns_zone_t *zone) { |
| 1273 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1274 | if (zone->raw != NULL) |
| 1275 | return (true); |
| 1276 | return (false); |
| 1277 | } |
| 1278 | |
| 1279 | /* |
| 1280 | * Returns true iff this the unsigned side of an inline-signing zone |
| 1281 | * Caller should hold zone lock. |
| 1282 | */ |
| 1283 | static inline bool |
| 1284 | inline_raw(dns_zone_t *zone) { |
| 1285 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1286 | if (zone->secure != NULL) |
| 1287 | return (true); |
| 1288 | return (false); |
| 1289 | } |
| 1290 | |
| 1291 | /* |
| 1292 | * Single shot. |
| 1293 | */ |
| 1294 | void |
| 1295 | dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) { |
| 1296 | char namebuf[1024]; |
| 1297 | |
| 1298 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1299 | REQUIRE(rdclass != dns_rdataclass_none); |
| 1300 | |
| 1301 | /* |
| 1302 | * Test and set. |
| 1303 | */ |
| 1304 | LOCK_ZONE(zone); |
| 1305 | INSIST(zone != zone->raw); |
| 1306 | REQUIRE(zone->rdclass == dns_rdataclass_none || |
| 1307 | zone->rdclass == rdclass); |
| 1308 | zone->rdclass = rdclass; |
| 1309 | |
| 1310 | if (zone->strnamerd != NULL) |
| 1311 | isc_mem_free(zone->mctx, zone->strnamerd); |
| 1312 | if (zone->strrdclass != NULL) |
| 1313 | isc_mem_free(zone->mctx, zone->strrdclass); |
| 1314 | |
| 1315 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
| 1316 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
| 1317 | zone_rdclass_tostr(zone, namebuf, sizeof namebuf); |
| 1318 | zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf); |
| 1319 | |
| 1320 | if (inline_secure(zone)) |
| 1321 | dns_zone_setclass(zone->raw, rdclass); |
| 1322 | UNLOCK_ZONE(zone); |
| 1323 | } |
| 1324 | |
| 1325 | dns_rdataclass_t |
| 1326 | dns_zone_getclass(dns_zone_t *zone) { |
| 1327 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1328 | |
| 1329 | return (zone->rdclass); |
| 1330 | } |
| 1331 | |
| 1332 | void |
| 1333 | dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) { |
| 1334 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1335 | |
| 1336 | LOCK_ZONE(zone); |
| 1337 | zone->notifytype = notifytype; |
| 1338 | UNLOCK_ZONE(zone); |
| 1339 | } |
| 1340 | |
| 1341 | isc_result_t |
| 1342 | dns_zone_getserial(dns_zone_t *zone, uint32_t *serialp) { |
| 1343 | isc_result_t result; |
| 1344 | unsigned int soacount; |
| 1345 | |
| 1346 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1347 | REQUIRE(serialp != NULL); |
| 1348 | |
| 1349 | LOCK_ZONE(zone); |
| 1350 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 1351 | if (zone->db != NULL) { |
| 1352 | result = zone_get_from_db(zone, zone->db, NULL, &soacount, |
| 1353 | serialp, NULL, NULL, NULL, NULL, |
| 1354 | NULL); |
| 1355 | if (result == ISC_R_SUCCESS && soacount == 0) |
| 1356 | result = ISC_R_FAILURE; |
| 1357 | } else |
| 1358 | result = DNS_R_NOTLOADED; |
| 1359 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 1360 | UNLOCK_ZONE(zone); |
| 1361 | |
| 1362 | return (result); |
| 1363 | } |
| 1364 | |
| 1365 | /* |
| 1366 | * Single shot. |
| 1367 | */ |
| 1368 | void |
| 1369 | dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) { |
| 1370 | char namebuf[1024]; |
| 1371 | |
| 1372 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1373 | REQUIRE(type != dns_zone_none); |
| 1374 | |
| 1375 | /* |
| 1376 | * Test and set. |
| 1377 | */ |
| 1378 | LOCK_ZONE(zone); |
| 1379 | REQUIRE(zone->type == dns_zone_none || zone->type == type); |
| 1380 | zone->type = type; |
| 1381 | |
| 1382 | if (zone->strnamerd != NULL) |
| 1383 | isc_mem_free(zone->mctx, zone->strnamerd); |
| 1384 | |
| 1385 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
| 1386 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
| 1387 | UNLOCK_ZONE(zone); |
| 1388 | } |
| 1389 | |
| 1390 | static void |
| 1391 | zone_freedbargs(dns_zone_t *zone) { |
| 1392 | unsigned int i; |
| 1393 | |
| 1394 | /* Free the old database argument list. */ |
| 1395 | if (zone->db_argv != NULL) { |
| 1396 | for (i = 0; i < zone->db_argc; i++) |
| 1397 | isc_mem_free(zone->mctx, zone->db_argv[i]); |
| 1398 | isc_mem_put(zone->mctx, zone->db_argv, |
| 1399 | zone->db_argc * sizeof(*zone->db_argv)); |
| 1400 | } |
| 1401 | zone->db_argc = 0; |
| 1402 | zone->db_argv = NULL; |
| 1403 | } |
| 1404 | |
| 1405 | isc_result_t |
| 1406 | dns_zone_getdbtype(dns_zone_t *zone, char ***argv, isc_mem_t *mctx) { |
| 1407 | size_t size = 0; |
| 1408 | unsigned int i; |
| 1409 | isc_result_t result = ISC_R_SUCCESS; |
| 1410 | void *mem; |
| 1411 | char **tmp, *tmp2, *base; |
| 1412 | |
| 1413 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1414 | REQUIRE(argv != NULL && *argv == NULL); |
| 1415 | |
| 1416 | LOCK_ZONE(zone); |
| 1417 | size = (zone->db_argc + 1) * sizeof(char *); |
| 1418 | for (i = 0; i < zone->db_argc; i++) |
| 1419 | size += strlen(zone->db_argv[i]) + 1; |
| 1420 | mem = isc_mem_allocate(mctx, size); |
| 1421 | if (mem != NULL) { |
| 1422 | tmp = mem; |
| 1423 | tmp2 = mem; |
| 1424 | base = mem; |
| 1425 | tmp2 += (zone->db_argc + 1) * sizeof(char *); |
| 1426 | for (i = 0; i < zone->db_argc; i++) { |
| 1427 | *tmp++ = tmp2; |
| 1428 | strlcpy(tmp2, zone->db_argv[i], size - (tmp2 - base)); |
| 1429 | tmp2 += strlen(tmp2) + 1; |
| 1430 | } |
| 1431 | *tmp = NULL; |
| 1432 | } else |
| 1433 | result = ISC_R_NOMEMORY; |
| 1434 | UNLOCK_ZONE(zone); |
| 1435 | *argv = mem; |
| 1436 | return (result); |
| 1437 | } |
| 1438 | |
| 1439 | isc_result_t |
| 1440 | dns_zone_setdbtype(dns_zone_t *zone, |
| 1441 | unsigned int dbargc, const char * const *dbargv) |
| 1442 | { |
| 1443 | isc_result_t result = ISC_R_SUCCESS; |
| 1444 | char **argv = NULL; |
| 1445 | unsigned int i; |
| 1446 | |
| 1447 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1448 | REQUIRE(dbargc >= 1); |
| 1449 | REQUIRE(dbargv != NULL); |
| 1450 | |
| 1451 | LOCK_ZONE(zone); |
| 1452 | |
| 1453 | /* Set up a new database argument list. */ |
| 1454 | argv = isc_mem_get(zone->mctx, dbargc * sizeof(*argv)); |
| 1455 | if (argv == NULL) { |
| 1456 | goto nomem; |
| 1457 | } |
| 1458 | for (i = 0; i < dbargc; i++) { |
| 1459 | argv[i] = NULL; |
| 1460 | } |
| 1461 | for (i = 0; i < dbargc; i++) { |
| 1462 | argv[i] = isc_mem_strdup(zone->mctx, dbargv[i]); |
| 1463 | if (argv[i] == NULL) |
| 1464 | goto nomem; |
| 1465 | } |
| 1466 | |
| 1467 | /* Free the old list. */ |
| 1468 | zone_freedbargs(zone); |
| 1469 | |
| 1470 | zone->db_argc = dbargc; |
| 1471 | zone->db_argv = argv; |
| 1472 | result = ISC_R_SUCCESS; |
| 1473 | goto unlock; |
| 1474 | |
| 1475 | nomem: |
| 1476 | if (argv != NULL) { |
| 1477 | for (i = 0; i < dbargc; i++) { |
| 1478 | if (argv[i] != NULL) { |
| 1479 | isc_mem_free(zone->mctx, argv[i]); |
| 1480 | } |
| 1481 | } |
| 1482 | isc_mem_put(zone->mctx, argv, dbargc * sizeof(*argv)); |
| 1483 | } |
| 1484 | result = ISC_R_NOMEMORY; |
| 1485 | |
| 1486 | unlock: |
| 1487 | UNLOCK_ZONE(zone); |
| 1488 | return (result); |
| 1489 | } |
| 1490 | |
| 1491 | static void |
| 1492 | dns_zone_setview_helper(dns_zone_t *zone, dns_view_t *view) { |
| 1493 | char namebuf[1024]; |
| 1494 | |
| 1495 | if (zone->prev_view == NULL && zone->view != NULL) { |
| 1496 | dns_view_weakattach(zone->view, &zone->prev_view); |
| 1497 | } |
| 1498 | |
| 1499 | INSIST(zone != zone->raw); |
| 1500 | if (zone->view != NULL) { |
| 1501 | dns_view_weakdetach(&zone->view); |
| 1502 | } |
| 1503 | dns_view_weakattach(view, &zone->view); |
| 1504 | |
| 1505 | if (zone->strviewname != NULL) { |
| 1506 | isc_mem_free(zone->mctx, zone->strviewname); |
| 1507 | } |
| 1508 | if (zone->strnamerd != NULL) { |
| 1509 | isc_mem_free(zone->mctx, zone->strnamerd); |
| 1510 | } |
| 1511 | |
| 1512 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
| 1513 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
| 1514 | zone_viewname_tostr(zone, namebuf, sizeof namebuf); |
| 1515 | zone->strviewname = isc_mem_strdup(zone->mctx, namebuf); |
| 1516 | |
| 1517 | if (inline_secure(zone)) { |
| 1518 | dns_zone_setview(zone->raw, view); |
| 1519 | } |
| 1520 | } |
| 1521 | |
| 1522 | void |
| 1523 | dns_zone_setview(dns_zone_t *zone, dns_view_t *view) { |
| 1524 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1525 | |
| 1526 | LOCK_ZONE(zone); |
| 1527 | dns_zone_setview_helper(zone, view); |
| 1528 | UNLOCK_ZONE(zone); |
| 1529 | } |
| 1530 | |
| 1531 | dns_view_t * |
| 1532 | dns_zone_getview(dns_zone_t *zone) { |
| 1533 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1534 | |
| 1535 | return (zone->view); |
| 1536 | } |
| 1537 | |
| 1538 | void |
| 1539 | dns_zone_setviewcommit(dns_zone_t *zone) { |
| 1540 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1541 | |
| 1542 | LOCK_ZONE(zone); |
| 1543 | if (zone->prev_view != NULL) |
| 1544 | dns_view_weakdetach(&zone->prev_view); |
| 1545 | UNLOCK_ZONE(zone); |
| 1546 | } |
| 1547 | |
| 1548 | void |
| 1549 | dns_zone_setviewrevert(dns_zone_t *zone) { |
| 1550 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1551 | |
| 1552 | LOCK_ZONE(zone); |
| 1553 | if (zone->prev_view != NULL) { |
| 1554 | dns_zone_setview_helper(zone, zone->prev_view); |
| 1555 | dns_view_weakdetach(&zone->prev_view); |
| 1556 | } |
| 1557 | UNLOCK_ZONE(zone); |
| 1558 | } |
| 1559 | |
| 1560 | isc_result_t |
| 1561 | dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) { |
| 1562 | isc_result_t result; |
| 1563 | char namebuf[1024]; |
| 1564 | |
| 1565 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1566 | REQUIRE(origin != NULL); |
| 1567 | |
| 1568 | LOCK_ZONE(zone); |
| 1569 | INSIST(zone != zone->raw); |
| 1570 | if (dns_name_dynamic(&zone->origin)) { |
| 1571 | dns_name_free(&zone->origin, zone->mctx); |
| 1572 | dns_name_init(&zone->origin, NULL); |
| 1573 | } |
| 1574 | result = dns_name_dup(origin, zone->mctx, &zone->origin); |
| 1575 | |
| 1576 | if (zone->strnamerd != NULL) |
| 1577 | isc_mem_free(zone->mctx, zone->strnamerd); |
| 1578 | if (zone->strname != NULL) |
| 1579 | isc_mem_free(zone->mctx, zone->strname); |
| 1580 | |
| 1581 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
| 1582 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
| 1583 | zone_name_tostr(zone, namebuf, sizeof namebuf); |
| 1584 | zone->strname = isc_mem_strdup(zone->mctx, namebuf); |
| 1585 | |
| 1586 | if (result == ISC_R_SUCCESS && inline_secure(zone)) |
| 1587 | result = dns_zone_setorigin(zone->raw, origin); |
| 1588 | UNLOCK_ZONE(zone); |
| 1589 | return (result); |
| 1590 | } |
| 1591 | |
| 1592 | static isc_result_t |
| 1593 | dns_zone_setstring(dns_zone_t *zone, char **field, const char *value) { |
| 1594 | char *copy; |
| 1595 | |
| 1596 | if (value != NULL) { |
| 1597 | copy = isc_mem_strdup(zone->mctx, value); |
| 1598 | if (copy == NULL) |
| 1599 | return (ISC_R_NOMEMORY); |
| 1600 | } else { |
| 1601 | copy = NULL; |
| 1602 | } |
| 1603 | |
| 1604 | if (*field != NULL) |
| 1605 | isc_mem_free(zone->mctx, *field); |
| 1606 | |
| 1607 | *field = copy; |
| 1608 | return (ISC_R_SUCCESS); |
| 1609 | } |
| 1610 | |
| 1611 | isc_result_t |
| 1612 | dns_zone_setfile(dns_zone_t *zone, const char *file, |
| 1613 | dns_masterformat_t format, |
| 1614 | const dns_master_style_t *style) |
| 1615 | { |
| 1616 | isc_result_t result = ISC_R_SUCCESS; |
| 1617 | |
| 1618 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1619 | |
| 1620 | LOCK_ZONE(zone); |
| 1621 | result = dns_zone_setstring(zone, &zone->masterfile, file); |
| 1622 | if (result == ISC_R_SUCCESS) { |
| 1623 | zone->masterformat = format; |
| 1624 | if (format == dns_masterformat_text) |
| 1625 | zone->masterstyle = style; |
| 1626 | result = default_journal(zone); |
| 1627 | } |
| 1628 | UNLOCK_ZONE(zone); |
| 1629 | |
| 1630 | return (result); |
| 1631 | } |
| 1632 | |
| 1633 | const char * |
| 1634 | dns_zone_getfile(dns_zone_t *zone) { |
| 1635 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1636 | |
| 1637 | return (zone->masterfile); |
| 1638 | } |
| 1639 | |
| 1640 | dns_ttl_t |
| 1641 | dns_zone_getmaxttl(dns_zone_t *zone) { |
| 1642 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1643 | |
| 1644 | return (zone->maxttl); |
| 1645 | } |
| 1646 | |
| 1647 | void |
| 1648 | dns_zone_setmaxttl(dns_zone_t *zone, dns_ttl_t maxttl) { |
| 1649 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1650 | |
| 1651 | LOCK_ZONE(zone); |
| 1652 | if (maxttl != 0) |
| 1653 | zone->options |= DNS_ZONEOPT_CHECKTTL; |
| 1654 | else |
| 1655 | zone->options &= ~DNS_ZONEOPT_CHECKTTL; |
| 1656 | zone->maxttl = maxttl; |
| 1657 | UNLOCK_ZONE(zone); |
| 1658 | |
| 1659 | return; |
| 1660 | } |
| 1661 | |
| 1662 | static isc_result_t |
| 1663 | default_journal(dns_zone_t *zone) { |
| 1664 | isc_result_t result; |
| 1665 | char *journal; |
| 1666 | |
| 1667 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1668 | REQUIRE(LOCKED_ZONE(zone)); |
| 1669 | |
| 1670 | if (zone->masterfile != NULL) { |
| 1671 | /* Calculate string length including '\0'. */ |
| 1672 | int len = strlen(zone->masterfile) + sizeof(".jnl" ); |
| 1673 | journal = isc_mem_allocate(zone->mctx, len); |
| 1674 | if (journal == NULL) |
| 1675 | return (ISC_R_NOMEMORY); |
| 1676 | strlcpy(journal, zone->masterfile, len); |
| 1677 | strlcat(journal, ".jnl" , len); |
| 1678 | } else { |
| 1679 | journal = NULL; |
| 1680 | } |
| 1681 | result = dns_zone_setstring(zone, &zone->journal, journal); |
| 1682 | if (journal != NULL) |
| 1683 | isc_mem_free(zone->mctx, journal); |
| 1684 | return (result); |
| 1685 | } |
| 1686 | |
| 1687 | isc_result_t |
| 1688 | dns_zone_setjournal(dns_zone_t *zone, const char *myjournal) { |
| 1689 | isc_result_t result = ISC_R_SUCCESS; |
| 1690 | |
| 1691 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1692 | |
| 1693 | LOCK_ZONE(zone); |
| 1694 | result = dns_zone_setstring(zone, &zone->journal, myjournal); |
| 1695 | UNLOCK_ZONE(zone); |
| 1696 | |
| 1697 | return (result); |
| 1698 | } |
| 1699 | |
| 1700 | char * |
| 1701 | dns_zone_getjournal(dns_zone_t *zone) { |
| 1702 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1703 | |
| 1704 | return (zone->journal); |
| 1705 | } |
| 1706 | |
| 1707 | /* |
| 1708 | * Return true iff the zone is "dynamic", in the sense that the zone's |
| 1709 | * master file (if any) is written by the server, rather than being |
| 1710 | * updated manually and read by the server. |
| 1711 | * |
| 1712 | * This is true for slave zones, mirror zones, stub zones, key zones, |
| 1713 | * and zones that allow dynamic updates either by having an update |
| 1714 | * policy ("ssutable") or an "allow-update" ACL with a value other than |
| 1715 | * exactly "{ none; }". |
| 1716 | */ |
| 1717 | bool |
| 1718 | dns_zone_isdynamic(dns_zone_t *zone, bool ignore_freeze) { |
| 1719 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1720 | |
| 1721 | if (zone->type == dns_zone_slave || zone->type == dns_zone_mirror || |
| 1722 | zone->type == dns_zone_stub || zone->type == dns_zone_key || |
| 1723 | (zone->type == dns_zone_redirect && zone->masters != NULL)) |
| 1724 | return (true); |
| 1725 | |
| 1726 | /* Inline zones are always dynamic. */ |
| 1727 | if (zone->type == dns_zone_master && zone->raw != NULL) |
| 1728 | return (true); |
| 1729 | |
| 1730 | /* If !ignore_freeze, we need check whether updates are disabled. */ |
| 1731 | if (zone->type == dns_zone_master && |
| 1732 | (!zone->update_disabled || ignore_freeze) && |
| 1733 | ((zone->ssutable != NULL) || |
| 1734 | (zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl)))) |
| 1735 | return (true); |
| 1736 | |
| 1737 | return (false); |
| 1738 | |
| 1739 | } |
| 1740 | |
| 1741 | /* |
| 1742 | * Set the response policy index and information for a zone. |
| 1743 | */ |
| 1744 | isc_result_t |
| 1745 | dns_zone_rpz_enable(dns_zone_t *zone, dns_rpz_zones_t *rpzs, |
| 1746 | dns_rpz_num_t rpz_num) |
| 1747 | { |
| 1748 | /* |
| 1749 | * Only RBTDB zones can be used for response policy zones, |
| 1750 | * because only they have the code to load the create the summary data. |
| 1751 | * Only zones that are loaded instead of mmap()ed create the |
| 1752 | * summary data and so can be policy zones. |
| 1753 | */ |
| 1754 | if (strcmp(zone->db_argv[0], "rbt" ) != 0 && |
| 1755 | strcmp(zone->db_argv[0], "rbt64" ) != 0) |
| 1756 | return (ISC_R_NOTIMPLEMENTED); |
| 1757 | if (zone->masterformat == dns_masterformat_map) |
| 1758 | return (ISC_R_NOTIMPLEMENTED); |
| 1759 | |
| 1760 | /* |
| 1761 | * This must happen only once or be redundant. |
| 1762 | */ |
| 1763 | LOCK_ZONE(zone); |
| 1764 | if (zone->rpzs != NULL) { |
| 1765 | REQUIRE(zone->rpzs == rpzs && zone->rpz_num == rpz_num); |
| 1766 | } else { |
| 1767 | REQUIRE(zone->rpz_num == DNS_RPZ_INVALID_NUM); |
| 1768 | dns_rpz_attach_rpzs(rpzs, &zone->rpzs); |
| 1769 | zone->rpz_num = rpz_num; |
| 1770 | } |
| 1771 | rpzs->defined |= DNS_RPZ_ZBIT(rpz_num); |
| 1772 | UNLOCK_ZONE(zone); |
| 1773 | |
| 1774 | return (ISC_R_SUCCESS); |
| 1775 | } |
| 1776 | |
| 1777 | dns_rpz_num_t |
| 1778 | dns_zone_get_rpz_num(dns_zone_t *zone) { |
| 1779 | return (zone->rpz_num); |
| 1780 | } |
| 1781 | |
| 1782 | /* |
| 1783 | * If a zone is a response policy zone, mark its new database. |
| 1784 | */ |
| 1785 | void |
| 1786 | dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db) { |
| 1787 | isc_result_t result; |
| 1788 | if (zone->rpz_num == DNS_RPZ_INVALID_NUM) { |
| 1789 | return; |
| 1790 | } |
| 1791 | REQUIRE(zone->rpzs != NULL); |
| 1792 | result = dns_db_updatenotify_register(db, |
| 1793 | dns_rpz_dbupdate_callback, |
| 1794 | zone->rpzs->zones[zone->rpz_num]); |
| 1795 | REQUIRE(result == ISC_R_SUCCESS); |
| 1796 | } |
| 1797 | |
| 1798 | static void |
| 1799 | dns_zone_rpz_disable_db(dns_zone_t *zone, dns_db_t *db) { |
| 1800 | if (zone->rpz_num == DNS_RPZ_INVALID_NUM) { |
| 1801 | return; |
| 1802 | } |
| 1803 | REQUIRE(zone->rpzs != NULL); |
| 1804 | (void) dns_db_updatenotify_unregister(db, |
| 1805 | dns_rpz_dbupdate_callback, |
| 1806 | zone->rpzs->zones[zone->rpz_num]); |
| 1807 | } |
| 1808 | |
| 1809 | void |
| 1810 | dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs) { |
| 1811 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1812 | REQUIRE(catzs != NULL); |
| 1813 | |
| 1814 | LOCK_ZONE(zone); |
| 1815 | INSIST(zone->catzs == NULL || zone->catzs == catzs); |
| 1816 | dns_catz_catzs_set_view(catzs, zone->view); |
| 1817 | if (zone->catzs == NULL) { |
| 1818 | dns_catz_catzs_attach(catzs, &zone->catzs); |
| 1819 | } |
| 1820 | UNLOCK_ZONE(zone); |
| 1821 | } |
| 1822 | |
| 1823 | /* |
| 1824 | * If a zone is a catalog zone, attach it to update notification in database. |
| 1825 | */ |
| 1826 | void |
| 1827 | dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db) { |
| 1828 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1829 | REQUIRE(db != NULL); |
| 1830 | |
| 1831 | if (zone->catzs != NULL) { |
| 1832 | dns_db_updatenotify_register(db, dns_catz_dbupdate_callback, |
| 1833 | zone->catzs); |
| 1834 | } |
| 1835 | } |
| 1836 | |
| 1837 | static void |
| 1838 | dns_zone_catz_disable_db(dns_zone_t *zone, dns_db_t *db) { |
| 1839 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1840 | REQUIRE(db != NULL); |
| 1841 | |
| 1842 | if (zone->catzs != NULL) { |
| 1843 | dns_db_updatenotify_unregister(db, dns_catz_dbupdate_callback, |
| 1844 | zone->catzs); |
| 1845 | } |
| 1846 | } |
| 1847 | |
| 1848 | /* |
| 1849 | * Set catalog zone ownership of the zone |
| 1850 | */ |
| 1851 | void |
| 1852 | dns_zone_set_parentcatz(dns_zone_t *zone, dns_catz_zone_t *catz) { |
| 1853 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1854 | REQUIRE(catz != NULL); |
| 1855 | LOCK_ZONE(zone); |
| 1856 | INSIST(zone->parentcatz == NULL || zone->parentcatz == catz); |
| 1857 | zone->parentcatz = catz; |
| 1858 | UNLOCK_ZONE(zone); |
| 1859 | } |
| 1860 | |
| 1861 | dns_catz_zone_t * |
| 1862 | dns_zone_get_parentcatz(const dns_zone_t *zone) { |
| 1863 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1864 | return (zone->parentcatz); |
| 1865 | } |
| 1866 | |
| 1867 | |
| 1868 | static bool |
| 1869 | zone_touched(dns_zone_t *zone) { |
| 1870 | isc_result_t result; |
| 1871 | isc_time_t modtime; |
| 1872 | dns_include_t *include; |
| 1873 | |
| 1874 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1875 | |
| 1876 | result = isc_file_getmodtime(zone->masterfile, &modtime); |
| 1877 | if (result != ISC_R_SUCCESS || |
| 1878 | isc_time_compare(&modtime, &zone->loadtime) > 0) |
| 1879 | return (true); |
| 1880 | |
| 1881 | for (include = ISC_LIST_HEAD(zone->includes); |
| 1882 | include != NULL; |
| 1883 | include = ISC_LIST_NEXT(include, link)) |
| 1884 | { |
| 1885 | result = isc_file_getmodtime(include->name, &modtime); |
| 1886 | if (result != ISC_R_SUCCESS || |
| 1887 | isc_time_compare(&modtime, &include->filetime) > 0) |
| 1888 | return (true); |
| 1889 | } |
| 1890 | |
| 1891 | return (false); |
| 1892 | } |
| 1893 | |
| 1894 | /* |
| 1895 | * Note: when dealing with inline-signed zones, external callers will always |
| 1896 | * call zone_load() for the secure zone; zone_load() calls itself recursively |
| 1897 | * in order to load the raw zone. |
| 1898 | */ |
| 1899 | static isc_result_t |
| 1900 | zone_load(dns_zone_t *zone, unsigned int flags, bool locked) { |
| 1901 | isc_result_t result; |
| 1902 | isc_time_t now; |
| 1903 | isc_time_t loadtime; |
| 1904 | dns_db_t *db = NULL; |
| 1905 | bool rbt, hasraw; |
| 1906 | |
| 1907 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 1908 | |
| 1909 | if (!locked) |
| 1910 | LOCK_ZONE(zone); |
| 1911 | |
| 1912 | INSIST(zone != zone->raw); |
| 1913 | hasraw = inline_secure(zone); |
| 1914 | if (hasraw) { |
| 1915 | /* |
| 1916 | * We are trying to load an inline-signed zone. First call |
| 1917 | * self recursively to try loading the raw version of the zone. |
| 1918 | * Assuming the raw zone file is readable, there are two |
| 1919 | * possibilities: |
| 1920 | * |
| 1921 | * a) the raw zone was not yet loaded and thus it will be |
| 1922 | * loaded now, synchronously; if this succeeds, a |
| 1923 | * subsequent attempt to load the signed zone file will |
| 1924 | * take place and thus zone_postload() will be called |
| 1925 | * twice: first for the raw zone and then for the secure |
| 1926 | * zone; the latter call will take care of syncing the raw |
| 1927 | * version with the secure version, |
| 1928 | * |
| 1929 | * b) the raw zone was already loaded and we are trying to |
| 1930 | * reload it, which will happen asynchronously; this means |
| 1931 | * zone_postload() will only be called for the raw zone |
| 1932 | * because "result" returned by the zone_load() call below |
| 1933 | * will not be ISC_R_SUCCESS but rather DNS_R_CONTINUE; |
| 1934 | * zone_postload() called for the raw zone will take care |
| 1935 | * of syncing the raw version with the secure version. |
| 1936 | */ |
| 1937 | result = zone_load(zone->raw, flags, false); |
| 1938 | if (result != ISC_R_SUCCESS) { |
| 1939 | if (!locked) |
| 1940 | UNLOCK_ZONE(zone); |
| 1941 | return(result); |
| 1942 | } |
| 1943 | LOCK_ZONE(zone->raw); |
| 1944 | } |
| 1945 | |
| 1946 | TIME_NOW(&now); |
| 1947 | |
| 1948 | INSIST(zone->type != dns_zone_none); |
| 1949 | |
| 1950 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) { |
| 1951 | if ((flags & DNS_ZONELOADFLAG_THAW) != 0) |
| 1952 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW); |
| 1953 | result = DNS_R_CONTINUE; |
| 1954 | goto cleanup; |
| 1955 | } |
| 1956 | |
| 1957 | INSIST(zone->db_argc >= 1); |
| 1958 | |
| 1959 | rbt = strcmp(zone->db_argv[0], "rbt" ) == 0 || |
| 1960 | strcmp(zone->db_argv[0], "rbt64" ) == 0; |
| 1961 | |
| 1962 | if (zone->db != NULL && zone->masterfile == NULL && rbt) { |
| 1963 | /* |
| 1964 | * The zone has no master file configured. |
| 1965 | */ |
| 1966 | result = ISC_R_SUCCESS; |
| 1967 | goto cleanup; |
| 1968 | } |
| 1969 | |
| 1970 | if (zone->db != NULL && dns_zone_isdynamic(zone, false)) { |
| 1971 | /* |
| 1972 | * This is a slave, stub, or dynamically updated |
| 1973 | * zone being reloaded. Do nothing - the database |
| 1974 | * we already have is guaranteed to be up-to-date. |
| 1975 | */ |
| 1976 | if (zone->type == dns_zone_master && !hasraw) |
| 1977 | result = DNS_R_DYNAMIC; |
| 1978 | else |
| 1979 | result = ISC_R_SUCCESS; |
| 1980 | goto cleanup; |
| 1981 | } |
| 1982 | |
| 1983 | /* |
| 1984 | * Store the current time before the zone is loaded, so that if the |
| 1985 | * file changes between the time of the load and the time that |
| 1986 | * zone->loadtime is set, then the file will still be reloaded |
| 1987 | * the next time dns_zone_load is called. |
| 1988 | */ |
| 1989 | TIME_NOW(&loadtime); |
| 1990 | |
| 1991 | /* |
| 1992 | * Don't do the load if the file that stores the zone is older |
| 1993 | * than the last time the zone was loaded. If the zone has not |
| 1994 | * been loaded yet, zone->loadtime will be the epoch. |
| 1995 | */ |
| 1996 | if (zone->masterfile != NULL) { |
| 1997 | isc_time_t filetime; |
| 1998 | |
| 1999 | /* |
| 2000 | * The file is already loaded. If we are just doing a |
| 2001 | * "rndc reconfig", we are done. |
| 2002 | */ |
| 2003 | if (!isc_time_isepoch(&zone->loadtime) && |
| 2004 | (flags & DNS_ZONELOADFLAG_NOSTAT) != 0) { |
| 2005 | result = ISC_R_SUCCESS; |
| 2006 | goto cleanup; |
| 2007 | } |
| 2008 | |
| 2009 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && |
| 2010 | !zone_touched(zone)) |
| 2011 | { |
| 2012 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 2013 | ISC_LOG_DEBUG(1), |
| 2014 | "skipping load: master file " |
| 2015 | "older than last load" ); |
| 2016 | result = DNS_R_UPTODATE; |
| 2017 | goto cleanup; |
| 2018 | } |
| 2019 | |
| 2020 | /* |
| 2021 | * If the file modification time is in the past |
| 2022 | * set loadtime to that value. |
| 2023 | */ |
| 2024 | result = isc_file_getmodtime(zone->masterfile, &filetime); |
| 2025 | if (result == ISC_R_SUCCESS && |
| 2026 | isc_time_compare(&loadtime, &filetime) > 0) |
| 2027 | loadtime = filetime; |
| 2028 | } |
| 2029 | |
| 2030 | /* |
| 2031 | * Built in zones (with the exception of empty zones) don't need |
| 2032 | * to be reloaded. |
| 2033 | */ |
| 2034 | if (zone->type == dns_zone_master && |
| 2035 | strcmp(zone->db_argv[0], "_builtin" ) == 0 && |
| 2036 | (zone->db_argc < 2 || strcmp(zone->db_argv[1], "empty" ) != 0) && |
| 2037 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { |
| 2038 | result = ISC_R_SUCCESS; |
| 2039 | goto cleanup; |
| 2040 | } |
| 2041 | |
| 2042 | /* |
| 2043 | * Zones associated with a DLZ don't need to be loaded either, |
| 2044 | * but we need to associate the database with the zone object. |
| 2045 | */ |
| 2046 | if (strcmp(zone->db_argv[0], "dlz" ) == 0) { |
| 2047 | dns_dlzdb_t *dlzdb; |
| 2048 | dns_dlzfindzone_t findzone; |
| 2049 | |
| 2050 | for (dlzdb = ISC_LIST_HEAD(zone->view->dlz_unsearched); |
| 2051 | dlzdb != NULL; |
| 2052 | dlzdb = ISC_LIST_NEXT(dlzdb, link)) |
| 2053 | { |
| 2054 | INSIST(DNS_DLZ_VALID(dlzdb)); |
| 2055 | if (strcmp(zone->db_argv[1], dlzdb->dlzname) == 0) |
| 2056 | break; |
| 2057 | } |
| 2058 | |
| 2059 | if (dlzdb == NULL) { |
| 2060 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 2061 | ISC_LOG_ERROR, |
| 2062 | "DLZ %s does not exist or is set " |
| 2063 | "to 'search yes;'" , zone->db_argv[1]); |
| 2064 | result = ISC_R_NOTFOUND; |
| 2065 | goto cleanup; |
| 2066 | } |
| 2067 | |
| 2068 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); |
| 2069 | /* ask SDLZ driver if the zone is supported */ |
| 2070 | findzone = dlzdb->implementation->methods->findzone; |
| 2071 | result = (*findzone)(dlzdb->implementation->driverarg, |
| 2072 | dlzdb->dbdata, dlzdb->mctx, |
| 2073 | zone->view->rdclass, &zone->origin, |
| 2074 | NULL, NULL, &db); |
| 2075 | if (result != ISC_R_NOTFOUND) { |
| 2076 | if (zone->db != NULL) |
| 2077 | zone_detachdb(zone); |
| 2078 | zone_attachdb(zone, db); |
| 2079 | dns_db_detach(&db); |
| 2080 | result = ISC_R_SUCCESS; |
| 2081 | } |
| 2082 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
| 2083 | |
| 2084 | if (result == ISC_R_SUCCESS) { |
| 2085 | if (dlzdb->configure_callback == NULL) |
| 2086 | goto cleanup; |
| 2087 | |
| 2088 | result = (*dlzdb->configure_callback)(zone->view, |
| 2089 | dlzdb, zone); |
| 2090 | if (result != ISC_R_SUCCESS) |
| 2091 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 2092 | ISC_LOG_ERROR, |
| 2093 | "DLZ configuration callback: %s" , |
| 2094 | isc_result_totext(result)); |
| 2095 | } |
| 2096 | goto cleanup; |
| 2097 | } |
| 2098 | |
| 2099 | if ((zone->type == dns_zone_slave || zone->type == dns_zone_mirror || |
| 2100 | zone->type == dns_zone_stub || |
| 2101 | (zone->type == dns_zone_redirect && zone->masters != NULL)) && |
| 2102 | rbt) { |
| 2103 | if (zone->masterfile == NULL || |
| 2104 | !isc_file_exists(zone->masterfile)) { |
| 2105 | if (zone->masterfile != NULL) { |
| 2106 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 2107 | ISC_LOG_DEBUG(1), |
| 2108 | "no master file" ); |
| 2109 | } |
| 2110 | zone->refreshtime = now; |
| 2111 | if (zone->task != NULL) |
| 2112 | zone_settimer(zone, &now); |
| 2113 | result = ISC_R_SUCCESS; |
| 2114 | goto cleanup; |
| 2115 | } |
| 2116 | } |
| 2117 | |
| 2118 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 2119 | ISC_LOG_DEBUG(1), "starting load" ); |
| 2120 | |
| 2121 | result = dns_db_create(zone->mctx, zone->db_argv[0], |
| 2122 | &zone->origin, (zone->type == dns_zone_stub) ? |
| 2123 | dns_dbtype_stub : dns_dbtype_zone, |
| 2124 | zone->rdclass, |
| 2125 | zone->db_argc - 1, zone->db_argv + 1, |
| 2126 | &db); |
| 2127 | |
| 2128 | if (result != ISC_R_SUCCESS) { |
| 2129 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_ERROR, |
| 2130 | "loading zone: creating database: %s" , |
| 2131 | isc_result_totext(result)); |
| 2132 | goto cleanup; |
| 2133 | } |
| 2134 | dns_db_settask(db, zone->task); |
| 2135 | |
| 2136 | if (zone->type == dns_zone_master || zone->type == dns_zone_slave || |
| 2137 | zone->type == dns_zone_mirror) |
| 2138 | { |
| 2139 | result = dns_db_setgluecachestats(db, zone->gluecachestats); |
| 2140 | if (result == ISC_R_NOTIMPLEMENTED) { |
| 2141 | result = ISC_R_SUCCESS; |
| 2142 | } |
| 2143 | if (result != ISC_R_SUCCESS) { |
| 2144 | goto cleanup; |
| 2145 | } |
| 2146 | } |
| 2147 | |
| 2148 | if (!dns_db_ispersistent(db)) { |
| 2149 | if (zone->masterfile != NULL) { |
| 2150 | result = zone_startload(db, zone, loadtime); |
| 2151 | } else { |
| 2152 | result = DNS_R_NOMASTERFILE; |
| 2153 | if (zone->type == dns_zone_master || |
| 2154 | (zone->type == dns_zone_redirect && |
| 2155 | zone->masters == NULL)) { |
| 2156 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 2157 | ISC_LOG_ERROR, |
| 2158 | "loading zone: " |
| 2159 | "no master file configured" ); |
| 2160 | goto cleanup; |
| 2161 | } |
| 2162 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 2163 | ISC_LOG_INFO, "loading zone: " |
| 2164 | "no master file configured: continuing" ); |
| 2165 | } |
| 2166 | } |
| 2167 | |
| 2168 | if (result == DNS_R_CONTINUE) { |
| 2169 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADING); |
| 2170 | if ((flags & DNS_ZONELOADFLAG_THAW) != 0) |
| 2171 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW); |
| 2172 | goto cleanup; |
| 2173 | } |
| 2174 | |
| 2175 | result = zone_postload(zone, db, loadtime, result); |
| 2176 | |
| 2177 | cleanup: |
| 2178 | if (hasraw) |
| 2179 | UNLOCK_ZONE(zone->raw); |
| 2180 | if (!locked) |
| 2181 | UNLOCK_ZONE(zone); |
| 2182 | if (db != NULL) |
| 2183 | dns_db_detach(&db); |
| 2184 | return (result); |
| 2185 | } |
| 2186 | |
| 2187 | isc_result_t |
| 2188 | dns_zone_load(dns_zone_t *zone, bool newonly) { |
| 2189 | return (zone_load(zone, newonly ? DNS_ZONELOADFLAG_NOSTAT : 0, false)); |
| 2190 | } |
| 2191 | |
| 2192 | static void |
| 2193 | zone_asyncload(isc_task_t *task, isc_event_t *event) { |
| 2194 | dns_asyncload_t *asl = event->ev_arg; |
| 2195 | dns_zone_t *zone = asl->zone; |
| 2196 | isc_result_t result; |
| 2197 | |
| 2198 | UNUSED(task); |
| 2199 | |
| 2200 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 2201 | |
| 2202 | isc_event_free(&event); |
| 2203 | |
| 2204 | LOCK_ZONE(zone); |
| 2205 | result = zone_load(zone, asl->flags, true); |
| 2206 | if (result != DNS_R_CONTINUE) { |
| 2207 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING); |
| 2208 | } |
| 2209 | UNLOCK_ZONE(zone); |
| 2210 | |
| 2211 | /* Inform the zone table we've finished loading */ |
| 2212 | if (asl->loaded != NULL) |
| 2213 | (asl->loaded)(asl->loaded_arg, zone, task); |
| 2214 | |
| 2215 | isc_mem_put(zone->mctx, asl, sizeof (*asl)); |
| 2216 | dns_zone_idetach(&zone); |
| 2217 | } |
| 2218 | |
| 2219 | isc_result_t |
| 2220 | dns_zone_asyncload(dns_zone_t *zone, bool newonly, |
| 2221 | dns_zt_zoneloaded_t done, void *arg) |
| 2222 | { |
| 2223 | isc_event_t *e; |
| 2224 | dns_asyncload_t *asl = NULL; |
| 2225 | isc_result_t result = ISC_R_SUCCESS; |
| 2226 | |
| 2227 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 2228 | |
| 2229 | if (zone->zmgr == NULL) |
| 2230 | return (ISC_R_FAILURE); |
| 2231 | |
| 2232 | /* If we already have a load pending, stop now */ |
| 2233 | LOCK_ZONE(zone); |
| 2234 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING)) { |
| 2235 | UNLOCK_ZONE(zone); |
| 2236 | return (ISC_R_ALREADYRUNNING); |
| 2237 | } |
| 2238 | |
| 2239 | asl = isc_mem_get(zone->mctx, sizeof (*asl)); |
| 2240 | if (asl == NULL) |
| 2241 | CHECK(ISC_R_NOMEMORY); |
| 2242 | |
| 2243 | asl->zone = NULL; |
| 2244 | asl->flags = newonly ? DNS_ZONELOADFLAG_NOSTAT : 0; |
| 2245 | asl->loaded = done; |
| 2246 | asl->loaded_arg = arg; |
| 2247 | |
| 2248 | e = isc_event_allocate(zone->zmgr->mctx, zone->zmgr, |
| 2249 | DNS_EVENT_ZONELOAD, |
| 2250 | zone_asyncload, asl, |
| 2251 | sizeof(isc_event_t)); |
| 2252 | if (e == NULL) |
| 2253 | CHECK(ISC_R_NOMEMORY); |
| 2254 | |
| 2255 | zone_iattach(zone, &asl->zone); |
| 2256 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADPENDING); |
| 2257 | isc_task_send(zone->loadtask, &e); |
| 2258 | UNLOCK_ZONE(zone); |
| 2259 | |
| 2260 | return (ISC_R_SUCCESS); |
| 2261 | |
| 2262 | failure: |
| 2263 | if (asl != NULL) |
| 2264 | isc_mem_put(zone->mctx, asl, sizeof (*asl)); |
| 2265 | UNLOCK_ZONE(zone); |
| 2266 | return (result); |
| 2267 | } |
| 2268 | |
| 2269 | bool |
| 2270 | dns__zone_loadpending(dns_zone_t *zone) { |
| 2271 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 2272 | |
| 2273 | return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING)); |
| 2274 | } |
| 2275 | |
| 2276 | isc_result_t |
| 2277 | dns_zone_loadandthaw(dns_zone_t *zone) { |
| 2278 | isc_result_t result; |
| 2279 | |
| 2280 | if (inline_raw(zone)) |
| 2281 | result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW, |
| 2282 | false); |
| 2283 | else |
| 2284 | result = zone_load(zone, DNS_ZONELOADFLAG_THAW, false); |
| 2285 | |
| 2286 | switch (result) { |
| 2287 | case DNS_R_CONTINUE: |
| 2288 | /* Deferred thaw. */ |
| 2289 | break; |
| 2290 | case DNS_R_UPTODATE: |
| 2291 | case ISC_R_SUCCESS: |
| 2292 | case DNS_R_SEENINCLUDE: |
| 2293 | zone->update_disabled = false; |
| 2294 | break; |
| 2295 | case DNS_R_NOMASTERFILE: |
| 2296 | zone->update_disabled = false; |
| 2297 | break; |
| 2298 | default: |
| 2299 | /* Error, remain in disabled state. */ |
| 2300 | break; |
| 2301 | } |
| 2302 | return (result); |
| 2303 | } |
| 2304 | |
| 2305 | static unsigned int |
| 2306 | get_master_options(dns_zone_t *zone) { |
| 2307 | unsigned int options; |
| 2308 | |
| 2309 | options = DNS_MASTER_ZONE | DNS_MASTER_RESIGN; |
| 2310 | if (zone->type == dns_zone_slave || zone->type == dns_zone_mirror || |
| 2311 | (zone->type == dns_zone_redirect && zone->masters == NULL)) |
| 2312 | { |
| 2313 | options |= DNS_MASTER_SLAVE; |
| 2314 | } |
| 2315 | if (zone->type == dns_zone_key) { |
| 2316 | options |= DNS_MASTER_KEY; |
| 2317 | } |
| 2318 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) { |
| 2319 | options |= DNS_MASTER_CHECKNS; |
| 2320 | } |
| 2321 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) { |
| 2322 | options |= DNS_MASTER_FATALNS; |
| 2323 | } |
| 2324 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES)) { |
| 2325 | options |= DNS_MASTER_CHECKNAMES; |
| 2326 | } |
| 2327 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) { |
| 2328 | options |= DNS_MASTER_CHECKNAMESFAIL; |
| 2329 | } |
| 2330 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX)) { |
| 2331 | options |= DNS_MASTER_CHECKMX; |
| 2332 | } |
| 2333 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) { |
| 2334 | options |= DNS_MASTER_CHECKMXFAIL; |
| 2335 | } |
| 2336 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD)) { |
| 2337 | options |= DNS_MASTER_CHECKWILDCARD; |
| 2338 | } |
| 2339 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKTTL)) { |
| 2340 | options |= DNS_MASTER_CHECKTTL; |
| 2341 | } |
| 2342 | |
| 2343 | return (options); |
| 2344 | } |
| 2345 | |
| 2346 | static void |
| 2347 | zone_registerinclude(const char *filename, void *arg) { |
| 2348 | isc_result_t result; |
| 2349 | dns_zone_t *zone = (dns_zone_t *) arg; |
| 2350 | dns_include_t *inc = NULL; |
| 2351 | |
| 2352 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 2353 | |
| 2354 | if (filename == NULL) |
| 2355 | return; |
| 2356 | |
| 2357 | /* |
| 2358 | * Suppress duplicates. |
| 2359 | */ |
| 2360 | for (inc = ISC_LIST_HEAD(zone->newincludes); |
| 2361 | inc != NULL; |
| 2362 | inc = ISC_LIST_NEXT(inc, link)) |
| 2363 | if (strcmp(filename, inc->name) == 0) |
| 2364 | return; |
| 2365 | |
| 2366 | inc = isc_mem_get(zone->mctx, sizeof(dns_include_t)); |
| 2367 | if (inc == NULL) |
| 2368 | return; |
| 2369 | inc->name = isc_mem_strdup(zone->mctx, filename); |
| 2370 | if (inc->name == NULL) { |
| 2371 | isc_mem_put(zone->mctx, inc, sizeof(dns_include_t)); |
| 2372 | return; |
| 2373 | } |
| 2374 | ISC_LINK_INIT(inc, link); |
| 2375 | |
| 2376 | result = isc_file_getmodtime(filename, &inc->filetime); |
| 2377 | if (result != ISC_R_SUCCESS) |
| 2378 | isc_time_settoepoch(&inc->filetime); |
| 2379 | |
| 2380 | ISC_LIST_APPEND(zone->newincludes, inc, link); |
| 2381 | } |
| 2382 | |
| 2383 | static void |
| 2384 | zone_gotreadhandle(isc_task_t *task, isc_event_t *event) { |
| 2385 | dns_load_t *load = event->ev_arg; |
| 2386 | isc_result_t result = ISC_R_SUCCESS; |
| 2387 | unsigned int options; |
| 2388 | |
| 2389 | REQUIRE(DNS_LOAD_VALID(load)); |
| 2390 | |
| 2391 | if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) |
| 2392 | result = ISC_R_CANCELED; |
| 2393 | isc_event_free(&event); |
| 2394 | if (result == ISC_R_CANCELED) |
| 2395 | goto fail; |
| 2396 | |
| 2397 | options = get_master_options(load->zone); |
| 2398 | |
| 2399 | result = dns_master_loadfileinc(load->zone->masterfile, |
| 2400 | dns_db_origin(load->db), |
| 2401 | dns_db_origin(load->db), |
| 2402 | load->zone->rdclass, options, 0, |
| 2403 | &load->callbacks, task, |
| 2404 | zone_loaddone, load, |
| 2405 | &load->zone->lctx, |
| 2406 | zone_registerinclude, |
| 2407 | load->zone, load->zone->mctx, |
| 2408 | load->zone->masterformat, |
| 2409 | load->zone->maxttl); |
| 2410 | if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE && |
| 2411 | result != DNS_R_SEENINCLUDE) |
| 2412 | goto fail; |
| 2413 | return; |
| 2414 | |
| 2415 | fail: |
| 2416 | zone_loaddone(load, result); |
| 2417 | } |
| 2418 | |
| 2419 | static void |
| 2420 | get_raw_serial(dns_zone_t *raw, dns_masterrawheader_t *rawdata) { |
| 2421 | isc_result_t result; |
| 2422 | unsigned int soacount; |
| 2423 | |
| 2424 | LOCK(&raw->lock); |
| 2425 | if (raw->db != NULL) { |
| 2426 | result = zone_get_from_db(raw, raw->db, NULL, &soacount, |
| 2427 | &rawdata->sourceserial, |
| 2428 | NULL, NULL, NULL, NULL, |
| 2429 | NULL); |
| 2430 | if (result == ISC_R_SUCCESS && soacount > 0U) |
| 2431 | rawdata->flags |= DNS_MASTERRAW_SOURCESERIALSET; |
| 2432 | } |
| 2433 | UNLOCK(&raw->lock); |
| 2434 | } |
| 2435 | |
| 2436 | static void |
| 2437 | zone_gotwritehandle(isc_task_t *task, isc_event_t *event) { |
| 2438 | const char me[] = "zone_gotwritehandle" ; |
| 2439 | dns_zone_t *zone = event->ev_arg; |
| 2440 | isc_result_t result = ISC_R_SUCCESS; |
| 2441 | dns_dbversion_t *version = NULL; |
| 2442 | dns_masterrawheader_t rawdata; |
| 2443 | |
| 2444 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 2445 | INSIST(task == zone->task); |
| 2446 | ENTER; |
| 2447 | |
| 2448 | if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) |
| 2449 | result = ISC_R_CANCELED; |
| 2450 | isc_event_free(&event); |
| 2451 | if (result == ISC_R_CANCELED) |
| 2452 | goto fail; |
| 2453 | |
| 2454 | LOCK_ZONE(zone); |
| 2455 | INSIST(zone != zone->raw); |
| 2456 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 2457 | if (zone->db != NULL) { |
| 2458 | const dns_master_style_t *output_style; |
| 2459 | |
| 2460 | dns_db_currentversion(zone->db, &version); |
| 2461 | dns_master_initrawheader(&rawdata); |
| 2462 | if (inline_secure(zone)) |
| 2463 | get_raw_serial(zone->raw, &rawdata); |
| 2464 | if (zone->type == dns_zone_key) |
| 2465 | output_style = &dns_master_style_keyzone; |
| 2466 | else if (zone->masterstyle != NULL) |
| 2467 | output_style = zone->masterstyle; |
| 2468 | else |
| 2469 | output_style = &dns_master_style_default; |
| 2470 | result = dns_master_dumpinc(zone->mctx, zone->db, version, |
| 2471 | output_style, zone->masterfile, |
| 2472 | zone->task, dump_done, zone, |
| 2473 | &zone->dctx, zone->masterformat, |
| 2474 | &rawdata); |
| 2475 | dns_db_closeversion(zone->db, &version, false); |
| 2476 | } else |
| 2477 | result = ISC_R_CANCELED; |
| 2478 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 2479 | UNLOCK_ZONE(zone); |
| 2480 | if (result != DNS_R_CONTINUE) |
| 2481 | goto fail; |
| 2482 | return; |
| 2483 | |
| 2484 | fail: |
| 2485 | dump_done(zone, result); |
| 2486 | } |
| 2487 | |
| 2488 | /* |
| 2489 | * Save the raw serial number for inline-signing zones. |
| 2490 | * (XXX: Other information from the header will be used |
| 2491 | * for other purposes in the future, but for now this is |
| 2492 | * all we're interested in.) |
| 2493 | */ |
| 2494 | static void |
| 2495 | zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *) { |
| 2496 | if ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0) |
| 2497 | return; |
| 2498 | |
| 2499 | zone->sourceserial = header->sourceserial; |
| 2500 | zone->sourceserialset = true; |
| 2501 | } |
| 2502 | |
| 2503 | void |
| 2504 | dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *) { |
| 2505 | if (zone == NULL) |
| 2506 | return; |
| 2507 | |
| 2508 | LOCK_ZONE(zone); |
| 2509 | zone_setrawdata(zone, header); |
| 2510 | UNLOCK_ZONE(zone); |
| 2511 | } |
| 2512 | |
| 2513 | static isc_result_t |
| 2514 | zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { |
| 2515 | const char me[] = "zone_startload" ; |
| 2516 | dns_load_t *load; |
| 2517 | isc_result_t result; |
| 2518 | isc_result_t tresult; |
| 2519 | unsigned int options; |
| 2520 | |
| 2521 | ENTER; |
| 2522 | |
| 2523 | dns_zone_rpz_enable_db(zone, db); |
| 2524 | dns_zone_catz_enable_db(zone, db); |
| 2525 | |
| 2526 | options = get_master_options(zone); |
| 2527 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS)) { |
| 2528 | options |= DNS_MASTER_MANYERRORS; |
| 2529 | } |
| 2530 | |
| 2531 | if (zone->zmgr != NULL && zone->db != NULL && zone->loadtask != NULL) { |
| 2532 | load = isc_mem_get(zone->mctx, sizeof(*load)); |
| 2533 | if (load == NULL) |
| 2534 | return (ISC_R_NOMEMORY); |
| 2535 | |
| 2536 | load->mctx = NULL; |
| 2537 | load->zone = NULL; |
| 2538 | load->db = NULL; |
| 2539 | load->loadtime = loadtime; |
| 2540 | load->magic = LOAD_MAGIC; |
| 2541 | |
| 2542 | isc_mem_attach(zone->mctx, &load->mctx); |
| 2543 | zone_iattach(zone, &load->zone); |
| 2544 | dns_db_attach(db, &load->db); |
| 2545 | dns_rdatacallbacks_init(&load->callbacks); |
| 2546 | load->callbacks.rawdata = zone_setrawdata; |
| 2547 | zone_iattach(zone, &load->callbacks.zone); |
| 2548 | result = dns_db_beginload(db, &load->callbacks); |
| 2549 | if (result != ISC_R_SUCCESS) { |
| 2550 | goto cleanup; |
| 2551 | } |
| 2552 | result = zonemgr_getio(zone->zmgr, true, zone->loadtask, |
| 2553 | zone_gotreadhandle, load, |
| 2554 | &zone->readio); |
| 2555 | if (result != ISC_R_SUCCESS) { |
| 2556 | /* |
| 2557 | * We can't report multiple errors so ignore |
| 2558 | * the result of dns_db_endload(). |
| 2559 | */ |
| 2560 | (void)dns_db_endload(load->db, &load->callbacks); |
| 2561 | goto cleanup; |
| 2562 | } else { |
| 2563 | result = DNS_R_CONTINUE; |
| 2564 | } |
| 2565 | } else { |
| 2566 | dns_rdatacallbacks_t callbacks; |
| 2567 | |
| 2568 | dns_rdatacallbacks_init(&callbacks); |
| 2569 | callbacks.rawdata = zone_setrawdata; |
| 2570 | zone_iattach(zone, &callbacks.zone); |
| 2571 | result = dns_db_beginload(db, &callbacks); |
| 2572 | if (result != ISC_R_SUCCESS) { |
| 2573 | zone_idetach(&callbacks.zone); |
| 2574 | return (result); |
| 2575 | } |
| 2576 | result = dns_master_loadfile(zone->masterfile, |
| 2577 | &zone->origin, &zone->origin, |
| 2578 | zone->rdclass, options, 0, |
| 2579 | &callbacks, |
| 2580 | zone_registerinclude, |
| 2581 | zone, zone->mctx, |
| 2582 | zone->masterformat, |
| 2583 | zone->maxttl); |
| 2584 | tresult = dns_db_endload(db, &callbacks); |
| 2585 | if (result == ISC_R_SUCCESS) { |
| 2586 | result = tresult; |
| 2587 | } |
| 2588 | zone_idetach(&callbacks.zone); |
| 2589 | } |
| 2590 | |
| 2591 | return (result); |
| 2592 | |
| 2593 | cleanup: |
| 2594 | load->magic = 0; |
| 2595 | dns_db_detach(&load->db); |
| 2596 | zone_idetach(&load->zone); |
| 2597 | zone_idetach(&load->callbacks.zone); |
| 2598 | isc_mem_detach(&load->mctx); |
| 2599 | isc_mem_put(zone->mctx, load, sizeof(*load)); |
| 2600 | return (result); |
| 2601 | } |
| 2602 | |
| 2603 | static bool |
| 2604 | zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, |
| 2605 | dns_name_t *owner) |
| 2606 | { |
| 2607 | isc_result_t result; |
| 2608 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
| 2609 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 2610 | char altbuf[DNS_NAME_FORMATSIZE]; |
| 2611 | dns_fixedname_t fixed; |
| 2612 | dns_name_t *foundname; |
| 2613 | int level; |
| 2614 | |
| 2615 | /* |
| 2616 | * "." means the services does not exist. |
| 2617 | */ |
| 2618 | if (dns_name_equal(name, dns_rootname)) |
| 2619 | return (true); |
| 2620 | |
| 2621 | /* |
| 2622 | * Outside of zone. |
| 2623 | */ |
| 2624 | if (!dns_name_issubdomain(name, &zone->origin)) { |
| 2625 | if (zone->checkmx != NULL) |
| 2626 | return ((zone->checkmx)(zone, name, owner)); |
| 2627 | return (true); |
| 2628 | } |
| 2629 | |
| 2630 | if (zone->type == dns_zone_master) |
| 2631 | level = ISC_LOG_ERROR; |
| 2632 | else |
| 2633 | level = ISC_LOG_WARNING; |
| 2634 | |
| 2635 | foundname = dns_fixedname_initname(&fixed); |
| 2636 | |
| 2637 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, |
| 2638 | 0, 0, NULL, foundname, NULL, NULL); |
| 2639 | if (result == ISC_R_SUCCESS) |
| 2640 | return (true); |
| 2641 | |
| 2642 | if (result == DNS_R_NXRRSET) { |
| 2643 | result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, |
| 2644 | 0, 0, NULL, foundname, NULL, NULL); |
| 2645 | if (result == ISC_R_SUCCESS) |
| 2646 | return (true); |
| 2647 | } |
| 2648 | |
| 2649 | dns_name_format(owner, ownerbuf, sizeof ownerbuf); |
| 2650 | dns_name_format(name, namebuf, sizeof namebuf); |
| 2651 | if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || |
| 2652 | result == DNS_R_EMPTYNAME) { |
| 2653 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) |
| 2654 | level = ISC_LOG_WARNING; |
| 2655 | dns_zone_log(zone, level, |
| 2656 | "%s/MX '%s' has no address records (A or AAAA)" , |
| 2657 | ownerbuf, namebuf); |
| 2658 | return ((level == ISC_LOG_WARNING) ? true : false); |
| 2659 | } |
| 2660 | |
| 2661 | if (result == DNS_R_CNAME) { |
| 2662 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) || |
| 2663 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) |
| 2664 | level = ISC_LOG_WARNING; |
| 2665 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) |
| 2666 | dns_zone_log(zone, level, |
| 2667 | "%s/MX '%s' is a CNAME (illegal)" , |
| 2668 | ownerbuf, namebuf); |
| 2669 | return ((level == ISC_LOG_WARNING) ? true : false); |
| 2670 | } |
| 2671 | |
| 2672 | if (result == DNS_R_DNAME) { |
| 2673 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) || |
| 2674 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) |
| 2675 | level = ISC_LOG_WARNING; |
| 2676 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) { |
| 2677 | dns_name_format(foundname, altbuf, sizeof altbuf); |
| 2678 | dns_zone_log(zone, level, "%s/MX '%s' is below a DNAME" |
| 2679 | " '%s' (illegal)" , ownerbuf, namebuf, |
| 2680 | altbuf); |
| 2681 | } |
| 2682 | return ((level == ISC_LOG_WARNING) ? true : false); |
| 2683 | } |
| 2684 | |
| 2685 | if (zone->checkmx != NULL && result == DNS_R_DELEGATION) |
| 2686 | return ((zone->checkmx)(zone, name, owner)); |
| 2687 | |
| 2688 | return (true); |
| 2689 | } |
| 2690 | |
| 2691 | static bool |
| 2692 | zone_check_srv(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, |
| 2693 | dns_name_t *owner) |
| 2694 | { |
| 2695 | isc_result_t result; |
| 2696 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
| 2697 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 2698 | char altbuf[DNS_NAME_FORMATSIZE]; |
| 2699 | dns_fixedname_t fixed; |
| 2700 | dns_name_t *foundname; |
| 2701 | int level; |
| 2702 | |
| 2703 | /* |
| 2704 | * "." means the services does not exist. |
| 2705 | */ |
| 2706 | if (dns_name_equal(name, dns_rootname)) |
| 2707 | return (true); |
| 2708 | |
| 2709 | /* |
| 2710 | * Outside of zone. |
| 2711 | */ |
| 2712 | if (!dns_name_issubdomain(name, &zone->origin)) { |
| 2713 | if (zone->checksrv != NULL) |
| 2714 | return ((zone->checksrv)(zone, name, owner)); |
| 2715 | return (true); |
| 2716 | } |
| 2717 | |
| 2718 | if (zone->type == dns_zone_master) |
| 2719 | level = ISC_LOG_ERROR; |
| 2720 | else |
| 2721 | level = ISC_LOG_WARNING; |
| 2722 | |
| 2723 | foundname = dns_fixedname_initname(&fixed); |
| 2724 | |
| 2725 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, |
| 2726 | 0, 0, NULL, foundname, NULL, NULL); |
| 2727 | if (result == ISC_R_SUCCESS) |
| 2728 | return (true); |
| 2729 | |
| 2730 | if (result == DNS_R_NXRRSET) { |
| 2731 | result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, |
| 2732 | 0, 0, NULL, foundname, NULL, NULL); |
| 2733 | if (result == ISC_R_SUCCESS) |
| 2734 | return (true); |
| 2735 | } |
| 2736 | |
| 2737 | dns_name_format(owner, ownerbuf, sizeof ownerbuf); |
| 2738 | dns_name_format(name, namebuf, sizeof namebuf); |
| 2739 | if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || |
| 2740 | result == DNS_R_EMPTYNAME) { |
| 2741 | dns_zone_log(zone, level, |
| 2742 | "%s/SRV '%s' has no address records (A or AAAA)" , |
| 2743 | ownerbuf, namebuf); |
| 2744 | /* XXX950 make fatal for 9.5.0. */ |
| 2745 | return (true); |
| 2746 | } |
| 2747 | |
| 2748 | if (result == DNS_R_CNAME) { |
| 2749 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNSRVCNAME) || |
| 2750 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) |
| 2751 | level = ISC_LOG_WARNING; |
| 2752 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) |
| 2753 | dns_zone_log(zone, level, |
| 2754 | "%s/SRV '%s' is a CNAME (illegal)" , |
| 2755 | ownerbuf, namebuf); |
| 2756 | return ((level == ISC_LOG_WARNING) ? true : false); |
| 2757 | } |
| 2758 | |
| 2759 | if (result == DNS_R_DNAME) { |
| 2760 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNSRVCNAME) || |
| 2761 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) |
| 2762 | level = ISC_LOG_WARNING; |
| 2763 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) { |
| 2764 | dns_name_format(foundname, altbuf, sizeof altbuf); |
| 2765 | dns_zone_log(zone, level, "%s/SRV '%s' is below a " |
| 2766 | "DNAME '%s' (illegal)" , ownerbuf, namebuf, |
| 2767 | altbuf); |
| 2768 | } |
| 2769 | return ((level == ISC_LOG_WARNING) ? true : false); |
| 2770 | } |
| 2771 | |
| 2772 | if (zone->checksrv != NULL && result == DNS_R_DELEGATION) |
| 2773 | return ((zone->checksrv)(zone, name, owner)); |
| 2774 | |
| 2775 | return (true); |
| 2776 | } |
| 2777 | |
| 2778 | static bool |
| 2779 | zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, |
| 2780 | dns_name_t *owner) |
| 2781 | { |
| 2782 | bool answer = true; |
| 2783 | isc_result_t result, tresult; |
| 2784 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
| 2785 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 2786 | char altbuf[DNS_NAME_FORMATSIZE]; |
| 2787 | dns_fixedname_t fixed; |
| 2788 | dns_name_t *foundname; |
| 2789 | dns_rdataset_t a; |
| 2790 | dns_rdataset_t aaaa; |
| 2791 | int level; |
| 2792 | |
| 2793 | /* |
| 2794 | * Outside of zone. |
| 2795 | */ |
| 2796 | if (!dns_name_issubdomain(name, &zone->origin)) { |
| 2797 | if (zone->checkns != NULL) |
| 2798 | return ((zone->checkns)(zone, name, owner, NULL, NULL)); |
| 2799 | return (true); |
| 2800 | } |
| 2801 | |
| 2802 | if (zone->type == dns_zone_master) |
| 2803 | level = ISC_LOG_ERROR; |
| 2804 | else |
| 2805 | level = ISC_LOG_WARNING; |
| 2806 | |
| 2807 | foundname = dns_fixedname_initname(&fixed); |
| 2808 | dns_rdataset_init(&a); |
| 2809 | dns_rdataset_init(&aaaa); |
| 2810 | |
| 2811 | /* |
| 2812 | * Perform a regular lookup to catch DNAME records then look |
| 2813 | * for glue. |
| 2814 | */ |
| 2815 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, |
| 2816 | 0, 0, NULL, foundname, &a, NULL); |
| 2817 | switch (result) { |
| 2818 | case ISC_R_SUCCESS: |
| 2819 | case DNS_R_DNAME: |
| 2820 | case DNS_R_CNAME: |
| 2821 | break; |
| 2822 | default: |
| 2823 | if (dns_rdataset_isassociated(&a)) |
| 2824 | dns_rdataset_disassociate(&a); |
| 2825 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, |
| 2826 | DNS_DBFIND_GLUEOK, 0, NULL, |
| 2827 | foundname, &a, NULL); |
| 2828 | } |
| 2829 | if (result == ISC_R_SUCCESS) { |
| 2830 | dns_rdataset_disassociate(&a); |
| 2831 | return (true); |
| 2832 | } else if (result == DNS_R_DELEGATION) |
| 2833 | dns_rdataset_disassociate(&a); |
| 2834 | |
| 2835 | if (result == DNS_R_NXRRSET || result == DNS_R_DELEGATION || |
| 2836 | result == DNS_R_GLUE) { |
| 2837 | tresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, |
| 2838 | DNS_DBFIND_GLUEOK, 0, NULL, |
| 2839 | foundname, &aaaa, NULL); |
| 2840 | if (tresult == ISC_R_SUCCESS) { |
| 2841 | if (dns_rdataset_isassociated(&a)) |
| 2842 | dns_rdataset_disassociate(&a); |
| 2843 | dns_rdataset_disassociate(&aaaa); |
| 2844 | return (true); |
| 2845 | } |
| 2846 | if (tresult == DNS_R_DELEGATION || tresult == DNS_R_DNAME) |
| 2847 | dns_rdataset_disassociate(&aaaa); |
| 2848 | if (result == DNS_R_GLUE || tresult == DNS_R_GLUE) { |
| 2849 | /* |
| 2850 | * Check glue against child zone. |
| 2851 | */ |
| 2852 | if (zone->checkns != NULL) |
| 2853 | answer = (zone->checkns)(zone, name, owner, |
| 2854 | &a, &aaaa); |
| 2855 | if (dns_rdataset_isassociated(&a)) |
| 2856 | dns_rdataset_disassociate(&a); |
| 2857 | if (dns_rdataset_isassociated(&aaaa)) |
| 2858 | dns_rdataset_disassociate(&aaaa); |
| 2859 | return (answer); |
| 2860 | } |
| 2861 | } |
| 2862 | |
| 2863 | dns_name_format(owner, ownerbuf, sizeof ownerbuf); |
| 2864 | dns_name_format(name, namebuf, sizeof namebuf); |
| 2865 | if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || |
| 2866 | result == DNS_R_EMPTYNAME || result == DNS_R_DELEGATION) { |
| 2867 | const char *what; |
| 2868 | bool required = false; |
| 2869 | if (dns_name_issubdomain(name, owner)) { |
| 2870 | what = "REQUIRED GLUE " ; |
| 2871 | required = true; |
| 2872 | } else if (result == DNS_R_DELEGATION) |
| 2873 | what = "SIBLING GLUE " ; |
| 2874 | else |
| 2875 | what = "" ; |
| 2876 | |
| 2877 | if (result != DNS_R_DELEGATION || required || |
| 2878 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSIBLING)) { |
| 2879 | dns_zone_log(zone, level, "%s/NS '%s' has no %s" |
| 2880 | "address records (A or AAAA)" , |
| 2881 | ownerbuf, namebuf, what); |
| 2882 | /* |
| 2883 | * Log missing address record. |
| 2884 | */ |
| 2885 | if (result == DNS_R_DELEGATION && zone->checkns != NULL) |
| 2886 | (void)(zone->checkns)(zone, name, owner, |
| 2887 | &a, &aaaa); |
| 2888 | /* XXX950 make fatal for 9.5.0. */ |
| 2889 | /* answer = false; */ |
| 2890 | } |
| 2891 | } else if (result == DNS_R_CNAME) { |
| 2892 | dns_zone_log(zone, level, "%s/NS '%s' is a CNAME (illegal)" , |
| 2893 | ownerbuf, namebuf); |
| 2894 | /* XXX950 make fatal for 9.5.0. */ |
| 2895 | /* answer = false; */ |
| 2896 | } else if (result == DNS_R_DNAME) { |
| 2897 | dns_name_format(foundname, altbuf, sizeof altbuf); |
| 2898 | dns_zone_log(zone, level, |
| 2899 | "%s/NS '%s' is below a DNAME '%s' (illegal)" , |
| 2900 | ownerbuf, namebuf, altbuf); |
| 2901 | /* XXX950 make fatal for 9.5.0. */ |
| 2902 | /* answer = false; */ |
| 2903 | } |
| 2904 | |
| 2905 | if (dns_rdataset_isassociated(&a)) |
| 2906 | dns_rdataset_disassociate(&a); |
| 2907 | if (dns_rdataset_isassociated(&aaaa)) |
| 2908 | dns_rdataset_disassociate(&aaaa); |
| 2909 | return (answer); |
| 2910 | } |
| 2911 | |
| 2912 | static bool |
| 2913 | zone_rrset_check_dup(dns_zone_t *zone, dns_name_t *owner, |
| 2914 | dns_rdataset_t *rdataset) |
| 2915 | { |
| 2916 | dns_rdataset_t tmprdataset; |
| 2917 | isc_result_t result; |
| 2918 | bool answer = true; |
| 2919 | bool format = true; |
| 2920 | int level = ISC_LOG_WARNING; |
| 2921 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
| 2922 | char typebuf[DNS_RDATATYPE_FORMATSIZE]; |
| 2923 | unsigned int count1 = 0; |
| 2924 | |
| 2925 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRRFAIL)) |
| 2926 | level = ISC_LOG_ERROR; |
| 2927 | |
| 2928 | dns_rdataset_init(&tmprdataset); |
| 2929 | for (result = dns_rdataset_first(rdataset); |
| 2930 | result == ISC_R_SUCCESS; |
| 2931 | result = dns_rdataset_next(rdataset)) { |
| 2932 | dns_rdata_t rdata1 = DNS_RDATA_INIT; |
| 2933 | unsigned int count2 = 0; |
| 2934 | |
| 2935 | count1++; |
| 2936 | dns_rdataset_current(rdataset, &rdata1); |
| 2937 | dns_rdataset_clone(rdataset, &tmprdataset); |
| 2938 | for (result = dns_rdataset_first(&tmprdataset); |
| 2939 | result == ISC_R_SUCCESS; |
| 2940 | result = dns_rdataset_next(&tmprdataset)) { |
| 2941 | dns_rdata_t rdata2 = DNS_RDATA_INIT; |
| 2942 | count2++; |
| 2943 | if (count1 >= count2) |
| 2944 | continue; |
| 2945 | dns_rdataset_current(&tmprdataset, &rdata2); |
| 2946 | if (dns_rdata_casecompare(&rdata1, &rdata2) == 0) { |
| 2947 | if (format) { |
| 2948 | dns_name_format(owner, ownerbuf, |
| 2949 | sizeof ownerbuf); |
| 2950 | dns_rdatatype_format(rdata1.type, |
| 2951 | typebuf, |
| 2952 | sizeof(typebuf)); |
| 2953 | format = false; |
| 2954 | } |
| 2955 | dns_zone_log(zone, level, "%s/%s has " |
| 2956 | "semantically identical records" , |
| 2957 | ownerbuf, typebuf); |
| 2958 | if (level == ISC_LOG_ERROR) |
| 2959 | answer = false; |
| 2960 | break; |
| 2961 | } |
| 2962 | } |
| 2963 | dns_rdataset_disassociate(&tmprdataset); |
| 2964 | if (!format) |
| 2965 | break; |
| 2966 | } |
| 2967 | return (answer); |
| 2968 | } |
| 2969 | |
| 2970 | static bool |
| 2971 | zone_check_dup(dns_zone_t *zone, dns_db_t *db) { |
| 2972 | dns_dbiterator_t *dbiterator = NULL; |
| 2973 | dns_dbnode_t *node = NULL; |
| 2974 | dns_fixedname_t fixed; |
| 2975 | dns_name_t *name; |
| 2976 | dns_rdataset_t rdataset; |
| 2977 | dns_rdatasetiter_t *rdsit = NULL; |
| 2978 | bool ok = true; |
| 2979 | isc_result_t result; |
| 2980 | |
| 2981 | name = dns_fixedname_initname(&fixed); |
| 2982 | dns_rdataset_init(&rdataset); |
| 2983 | |
| 2984 | result = dns_db_createiterator(db, 0, &dbiterator); |
| 2985 | if (result != ISC_R_SUCCESS) |
| 2986 | return (true); |
| 2987 | |
| 2988 | for (result = dns_dbiterator_first(dbiterator); |
| 2989 | result == ISC_R_SUCCESS; |
| 2990 | result = dns_dbiterator_next(dbiterator)) { |
| 2991 | result = dns_dbiterator_current(dbiterator, &node, name); |
| 2992 | if (result != ISC_R_SUCCESS) |
| 2993 | continue; |
| 2994 | |
| 2995 | result = dns_db_allrdatasets(db, node, NULL, 0, &rdsit); |
| 2996 | if (result != ISC_R_SUCCESS) |
| 2997 | continue; |
| 2998 | |
| 2999 | for (result = dns_rdatasetiter_first(rdsit); |
| 3000 | result == ISC_R_SUCCESS; |
| 3001 | result = dns_rdatasetiter_next(rdsit)) { |
| 3002 | dns_rdatasetiter_current(rdsit, &rdataset); |
| 3003 | if (!zone_rrset_check_dup(zone, name, &rdataset)) |
| 3004 | ok = false; |
| 3005 | dns_rdataset_disassociate(&rdataset); |
| 3006 | } |
| 3007 | dns_rdatasetiter_destroy(&rdsit); |
| 3008 | dns_db_detachnode(db, &node); |
| 3009 | } |
| 3010 | |
| 3011 | if (node != NULL) |
| 3012 | dns_db_detachnode(db, &node); |
| 3013 | dns_dbiterator_destroy(&dbiterator); |
| 3014 | |
| 3015 | return (ok); |
| 3016 | } |
| 3017 | |
| 3018 | static bool |
| 3019 | isspf(const dns_rdata_t *rdata) { |
| 3020 | char buf[1024]; |
| 3021 | const unsigned char *data = rdata->data; |
| 3022 | unsigned int rdl = rdata->length, i = 0, tl, len; |
| 3023 | |
| 3024 | while (rdl > 0U) { |
| 3025 | len = tl = *data; |
| 3026 | ++data; |
| 3027 | --rdl; |
| 3028 | INSIST(tl <= rdl); |
| 3029 | if (len > sizeof(buf) - i - 1) |
| 3030 | len = sizeof(buf) - i - 1; |
| 3031 | memmove(buf + i, data, len); |
| 3032 | i += len; |
| 3033 | data += tl; |
| 3034 | rdl -= tl; |
| 3035 | } |
| 3036 | |
| 3037 | if (i < 6U) |
| 3038 | return(false); |
| 3039 | |
| 3040 | buf[i] = 0; |
| 3041 | if (strncmp(buf, "v=spf1" , 6) == 0 && (buf[6] == 0 || buf[6] == ' ')) |
| 3042 | return (true); |
| 3043 | return (false); |
| 3044 | } |
| 3045 | |
| 3046 | static bool |
| 3047 | integrity_checks(dns_zone_t *zone, dns_db_t *db) { |
| 3048 | dns_dbiterator_t *dbiterator = NULL; |
| 3049 | dns_dbnode_t *node = NULL; |
| 3050 | dns_rdataset_t rdataset; |
| 3051 | dns_fixedname_t fixed; |
| 3052 | dns_fixedname_t fixedbottom; |
| 3053 | dns_rdata_mx_t mx; |
| 3054 | dns_rdata_ns_t ns; |
| 3055 | dns_rdata_in_srv_t srv; |
| 3056 | dns_rdata_t rdata; |
| 3057 | dns_name_t *name; |
| 3058 | dns_name_t *bottom; |
| 3059 | isc_result_t result; |
| 3060 | bool ok = true, have_spf, have_txt; |
| 3061 | |
| 3062 | name = dns_fixedname_initname(&fixed); |
| 3063 | bottom = dns_fixedname_initname(&fixedbottom); |
| 3064 | dns_rdataset_init(&rdataset); |
| 3065 | dns_rdata_init(&rdata); |
| 3066 | |
| 3067 | result = dns_db_createiterator(db, 0, &dbiterator); |
| 3068 | if (result != ISC_R_SUCCESS) |
| 3069 | return (true); |
| 3070 | |
| 3071 | result = dns_dbiterator_first(dbiterator); |
| 3072 | while (result == ISC_R_SUCCESS) { |
| 3073 | result = dns_dbiterator_current(dbiterator, &node, name); |
| 3074 | if (result != ISC_R_SUCCESS) |
| 3075 | goto cleanup; |
| 3076 | |
| 3077 | /* |
| 3078 | * Is this name visible in the zone? |
| 3079 | */ |
| 3080 | if (!dns_name_issubdomain(name, &zone->origin) || |
| 3081 | (dns_name_countlabels(bottom) > 0 && |
| 3082 | dns_name_issubdomain(name, bottom))) |
| 3083 | goto next; |
| 3084 | |
| 3085 | /* |
| 3086 | * Don't check the NS records at the origin. |
| 3087 | */ |
| 3088 | if (dns_name_equal(name, &zone->origin)) |
| 3089 | goto checkfordname; |
| 3090 | |
| 3091 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ns, |
| 3092 | 0, 0, &rdataset, NULL); |
| 3093 | if (result != ISC_R_SUCCESS) |
| 3094 | goto checkfordname; |
| 3095 | /* |
| 3096 | * Remember bottom of zone due to NS. |
| 3097 | */ |
| 3098 | dns_name_copy(name, bottom, NULL); |
| 3099 | |
| 3100 | result = dns_rdataset_first(&rdataset); |
| 3101 | while (result == ISC_R_SUCCESS) { |
| 3102 | dns_rdataset_current(&rdataset, &rdata); |
| 3103 | result = dns_rdata_tostruct(&rdata, &ns, NULL); |
| 3104 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 3105 | if (!zone_check_glue(zone, db, &ns.name, name)) |
| 3106 | ok = false; |
| 3107 | dns_rdata_reset(&rdata); |
| 3108 | result = dns_rdataset_next(&rdataset); |
| 3109 | } |
| 3110 | dns_rdataset_disassociate(&rdataset); |
| 3111 | goto next; |
| 3112 | |
| 3113 | checkfordname: |
| 3114 | result = dns_db_findrdataset(db, node, NULL, |
| 3115 | dns_rdatatype_dname, 0, 0, |
| 3116 | &rdataset, NULL); |
| 3117 | if (result == ISC_R_SUCCESS) { |
| 3118 | /* |
| 3119 | * Remember bottom of zone due to DNAME. |
| 3120 | */ |
| 3121 | dns_name_copy(name, bottom, NULL); |
| 3122 | dns_rdataset_disassociate(&rdataset); |
| 3123 | } |
| 3124 | |
| 3125 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx, |
| 3126 | 0, 0, &rdataset, NULL); |
| 3127 | if (result != ISC_R_SUCCESS) |
| 3128 | goto checksrv; |
| 3129 | result = dns_rdataset_first(&rdataset); |
| 3130 | while (result == ISC_R_SUCCESS) { |
| 3131 | dns_rdataset_current(&rdataset, &rdata); |
| 3132 | result = dns_rdata_tostruct(&rdata, &mx, NULL); |
| 3133 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 3134 | if (!zone_check_mx(zone, db, &mx.mx, name)) |
| 3135 | ok = false; |
| 3136 | dns_rdata_reset(&rdata); |
| 3137 | result = dns_rdataset_next(&rdataset); |
| 3138 | } |
| 3139 | dns_rdataset_disassociate(&rdataset); |
| 3140 | |
| 3141 | checksrv: |
| 3142 | if (zone->rdclass != dns_rdataclass_in) |
| 3143 | goto next; |
| 3144 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_srv, |
| 3145 | 0, 0, &rdataset, NULL); |
| 3146 | if (result != ISC_R_SUCCESS) |
| 3147 | goto checkspf; |
| 3148 | result = dns_rdataset_first(&rdataset); |
| 3149 | while (result == ISC_R_SUCCESS) { |
| 3150 | dns_rdataset_current(&rdataset, &rdata); |
| 3151 | result = dns_rdata_tostruct(&rdata, &srv, NULL); |
| 3152 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 3153 | if (!zone_check_srv(zone, db, &srv.target, name)) |
| 3154 | ok = false; |
| 3155 | dns_rdata_reset(&rdata); |
| 3156 | result = dns_rdataset_next(&rdataset); |
| 3157 | } |
| 3158 | dns_rdataset_disassociate(&rdataset); |
| 3159 | |
| 3160 | checkspf: |
| 3161 | /* |
| 3162 | * Check if there is a type SPF record without an |
| 3163 | * SPF-formatted type TXT record also being present. |
| 3164 | */ |
| 3165 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSPF)) |
| 3166 | goto next; |
| 3167 | if (zone->rdclass != dns_rdataclass_in) |
| 3168 | goto next; |
| 3169 | have_spf = have_txt = false; |
| 3170 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_spf, |
| 3171 | 0, 0, &rdataset, NULL); |
| 3172 | if (result == ISC_R_SUCCESS) { |
| 3173 | dns_rdataset_disassociate(&rdataset); |
| 3174 | have_spf = true; |
| 3175 | } |
| 3176 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_txt, |
| 3177 | 0, 0, &rdataset, NULL); |
| 3178 | if (result != ISC_R_SUCCESS) |
| 3179 | goto notxt; |
| 3180 | result = dns_rdataset_first(&rdataset); |
| 3181 | while (result == ISC_R_SUCCESS) { |
| 3182 | dns_rdataset_current(&rdataset, &rdata); |
| 3183 | have_txt = isspf(&rdata); |
| 3184 | dns_rdata_reset(&rdata); |
| 3185 | if (have_txt) |
| 3186 | break; |
| 3187 | result = dns_rdataset_next(&rdataset); |
| 3188 | } |
| 3189 | dns_rdataset_disassociate(&rdataset); |
| 3190 | |
| 3191 | notxt: |
| 3192 | if (have_spf && !have_txt) { |
| 3193 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 3194 | |
| 3195 | dns_name_format(name, namebuf, sizeof(namebuf)); |
| 3196 | dns_zone_log(zone, ISC_LOG_WARNING, "'%s' found type " |
| 3197 | "SPF record but no SPF TXT record found, " |
| 3198 | "add matching type TXT record" , namebuf); |
| 3199 | } |
| 3200 | |
| 3201 | next: |
| 3202 | dns_db_detachnode(db, &node); |
| 3203 | result = dns_dbiterator_next(dbiterator); |
| 3204 | } |
| 3205 | |
| 3206 | cleanup: |
| 3207 | if (node != NULL) |
| 3208 | dns_db_detachnode(db, &node); |
| 3209 | dns_dbiterator_destroy(&dbiterator); |
| 3210 | |
| 3211 | return (ok); |
| 3212 | } |
| 3213 | |
| 3214 | /* |
| 3215 | * OpenSSL verification of RSA keys with exponent 3 is known to be |
| 3216 | * broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn |
| 3217 | * if they are in use. |
| 3218 | */ |
| 3219 | static void |
| 3220 | zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) { |
| 3221 | dns_dbnode_t *node = NULL; |
| 3222 | dns_dbversion_t *version = NULL; |
| 3223 | dns_rdata_dnskey_t dnskey; |
| 3224 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3225 | dns_rdataset_t rdataset; |
| 3226 | isc_result_t result; |
| 3227 | bool logit, foundrsa = false; |
| 3228 | const char *algorithm; |
| 3229 | |
| 3230 | result = dns_db_findnode(db, &zone->origin, false, &node); |
| 3231 | if (result != ISC_R_SUCCESS) { |
| 3232 | goto cleanup; |
| 3233 | } |
| 3234 | |
| 3235 | dns_db_currentversion(db, &version); |
| 3236 | dns_rdataset_init(&rdataset); |
| 3237 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, |
| 3238 | dns_rdatatype_none, 0, &rdataset, NULL); |
| 3239 | if (result != ISC_R_SUCCESS) { |
| 3240 | goto cleanup; |
| 3241 | } |
| 3242 | |
| 3243 | for (result = dns_rdataset_first(&rdataset); |
| 3244 | result == ISC_R_SUCCESS; |
| 3245 | result = dns_rdataset_next(&rdataset)) |
| 3246 | { |
| 3247 | dns_rdataset_current(&rdataset, &rdata); |
| 3248 | result = dns_rdata_tostruct(&rdata, &dnskey, NULL); |
| 3249 | INSIST(result == ISC_R_SUCCESS); |
| 3250 | |
| 3251 | /* RFC 3110, section 4: Performance Considerations: |
| 3252 | * |
| 3253 | * A public exponent of 3 minimizes the effort needed to verify |
| 3254 | * a signature. Use of 3 as the public exponent is weak for |
| 3255 | * confidentiality uses since, if the same data can be collected |
| 3256 | * encrypted under three different keys with an exponent of 3 |
| 3257 | * then, using the Chinese Remainder Theorem [NETSEC], the |
| 3258 | * original plain text can be easily recovered. If a key is |
| 3259 | * known to be used only for authentication, as is the case with |
| 3260 | * DNSSEC, then an exponent of 3 is acceptable. However other |
| 3261 | * applications in the future may wish to leverage DNS |
| 3262 | * distributed keys for applications that do require |
| 3263 | * confidentiality. For keys which might have such other uses, |
| 3264 | * a more conservative choice would be 65537 (F4, the fourth |
| 3265 | * fermat number). |
| 3266 | */ |
| 3267 | if (dnskey.algorithm == DST_ALG_RSASHA1 && |
| 3268 | dnskey.datalen > 1 && dnskey.data[0] == 1 && |
| 3269 | dnskey.data[1] == 3) |
| 3270 | { |
| 3271 | if (dnskey.algorithm == DST_ALG_RSASHA1) { |
| 3272 | logit = !foundrsa; |
| 3273 | foundrsa = true; |
| 3274 | algorithm = "RSASHA1" ; |
| 3275 | } |
| 3276 | if (logit) { |
| 3277 | dnssec_log(zone, ISC_LOG_WARNING, |
| 3278 | "weak %s (%u) key found " |
| 3279 | "(exponent=3)" , algorithm, |
| 3280 | dnskey.algorithm); |
| 3281 | } |
| 3282 | } |
| 3283 | dns_rdata_reset(&rdata); |
| 3284 | } |
| 3285 | dns_rdataset_disassociate(&rdataset); |
| 3286 | |
| 3287 | cleanup: |
| 3288 | if (node != NULL) { |
| 3289 | dns_db_detachnode(db, &node); |
| 3290 | } |
| 3291 | if (version != NULL) { |
| 3292 | dns_db_closeversion(db, &version, false); |
| 3293 | } |
| 3294 | } |
| 3295 | |
| 3296 | static void |
| 3297 | resume_signingwithkey(dns_zone_t *zone) { |
| 3298 | dns_dbnode_t *node = NULL; |
| 3299 | dns_dbversion_t *version = NULL; |
| 3300 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3301 | dns_rdataset_t rdataset; |
| 3302 | isc_result_t result; |
| 3303 | dns_db_t *db = NULL; |
| 3304 | |
| 3305 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 3306 | if (zone->db != NULL) { |
| 3307 | dns_db_attach(zone->db, &db); |
| 3308 | } |
| 3309 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 3310 | if (db == NULL) { |
| 3311 | goto cleanup; |
| 3312 | } |
| 3313 | |
| 3314 | result = dns_db_findnode(db, &zone->origin, false, &node); |
| 3315 | if (result != ISC_R_SUCCESS) { |
| 3316 | goto cleanup; |
| 3317 | } |
| 3318 | |
| 3319 | dns_db_currentversion(db, &version); |
| 3320 | dns_rdataset_init(&rdataset); |
| 3321 | result = dns_db_findrdataset(db, node, version, |
| 3322 | zone->privatetype, |
| 3323 | dns_rdatatype_none, 0, |
| 3324 | &rdataset, NULL); |
| 3325 | if (result != ISC_R_SUCCESS) { |
| 3326 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 3327 | goto cleanup; |
| 3328 | } |
| 3329 | |
| 3330 | for (result = dns_rdataset_first(&rdataset); |
| 3331 | result == ISC_R_SUCCESS; |
| 3332 | result = dns_rdataset_next(&rdataset)) |
| 3333 | { |
| 3334 | dns_rdataset_current(&rdataset, &rdata); |
| 3335 | if (rdata.length != 5 || |
| 3336 | rdata.data[0] == 0 || rdata.data[4] != 0) |
| 3337 | { |
| 3338 | dns_rdata_reset(&rdata); |
| 3339 | continue; |
| 3340 | } |
| 3341 | |
| 3342 | result = zone_signwithkey(zone, rdata.data[0], |
| 3343 | (rdata.data[1] << 8) | rdata.data[2], |
| 3344 | rdata.data[3]); |
| 3345 | if (result != ISC_R_SUCCESS) { |
| 3346 | dnssec_log(zone, ISC_LOG_ERROR, |
| 3347 | "zone_signwithkey failed: %s" , |
| 3348 | dns_result_totext(result)); |
| 3349 | } |
| 3350 | dns_rdata_reset(&rdata); |
| 3351 | } |
| 3352 | dns_rdataset_disassociate(&rdataset); |
| 3353 | |
| 3354 | cleanup: |
| 3355 | if (db != NULL) { |
| 3356 | if (node != NULL) { |
| 3357 | dns_db_detachnode(db, &node); |
| 3358 | } |
| 3359 | if (version != NULL) { |
| 3360 | dns_db_closeversion(db, &version, false); |
| 3361 | } |
| 3362 | dns_db_detach(&db); |
| 3363 | } |
| 3364 | } |
| 3365 | |
| 3366 | /* |
| 3367 | * Initiate adding/removing NSEC3 records belonging to the chain defined by the |
| 3368 | * supplied NSEC3PARAM RDATA. |
| 3369 | * |
| 3370 | * Zone must be locked by caller. |
| 3371 | */ |
| 3372 | static isc_result_t |
| 3373 | zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { |
| 3374 | dns_nsec3chain_t *nsec3chain, *current; |
| 3375 | dns_dbversion_t *version = NULL; |
| 3376 | bool nseconly = false, nsec3ok = false; |
| 3377 | isc_result_t result; |
| 3378 | isc_time_t now; |
| 3379 | unsigned int options = 0; |
| 3380 | char saltbuf[255*2+1]; |
| 3381 | char flags[sizeof("INITIAL|REMOVE|CREATE|NONSEC|OPTOUT" )]; |
| 3382 | dns_db_t *db = NULL; |
| 3383 | |
| 3384 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 3385 | if (zone->db != NULL) { |
| 3386 | dns_db_attach(zone->db, &db); |
| 3387 | } |
| 3388 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 3389 | |
| 3390 | if (db == NULL) { |
| 3391 | result = ISC_R_SUCCESS; |
| 3392 | goto cleanup; |
| 3393 | } |
| 3394 | |
| 3395 | /* |
| 3396 | * If this zone is not NSEC3-capable, attempting to remove any NSEC3 |
| 3397 | * chain from it is pointless as it would not be possible for the |
| 3398 | * latter to exist in the first place. |
| 3399 | */ |
| 3400 | dns_db_currentversion(db, &version); |
| 3401 | result = dns_nsec_nseconly(db, version, &nseconly); |
| 3402 | nsec3ok = (result == ISC_R_SUCCESS && !nseconly); |
| 3403 | dns_db_closeversion(db, &version, false); |
| 3404 | if (!nsec3ok && (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) == 0) { |
| 3405 | result = ISC_R_SUCCESS; |
| 3406 | goto cleanup; |
| 3407 | } |
| 3408 | |
| 3409 | /* |
| 3410 | * Allocate and initialize structure preserving state of |
| 3411 | * adding/removing records belonging to this NSEC3 chain between |
| 3412 | * separate zone_nsec3chain() calls. |
| 3413 | */ |
| 3414 | nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain); |
| 3415 | if (nsec3chain == NULL) { |
| 3416 | result = ISC_R_NOMEMORY; |
| 3417 | goto cleanup; |
| 3418 | } |
| 3419 | |
| 3420 | nsec3chain->magic = 0; |
| 3421 | nsec3chain->done = false; |
| 3422 | nsec3chain->db = NULL; |
| 3423 | nsec3chain->dbiterator = NULL; |
| 3424 | nsec3chain->nsec3param.common.rdclass = nsec3param->common.rdclass; |
| 3425 | nsec3chain->nsec3param.common.rdtype = nsec3param->common.rdtype; |
| 3426 | nsec3chain->nsec3param.hash = nsec3param->hash; |
| 3427 | nsec3chain->nsec3param.iterations = nsec3param->iterations; |
| 3428 | nsec3chain->nsec3param.flags = nsec3param->flags; |
| 3429 | nsec3chain->nsec3param.salt_length = nsec3param->salt_length; |
| 3430 | memmove(nsec3chain->salt, nsec3param->salt, nsec3param->salt_length); |
| 3431 | nsec3chain->nsec3param.salt = nsec3chain->salt; |
| 3432 | nsec3chain->seen_nsec = false; |
| 3433 | nsec3chain->delete_nsec = false; |
| 3434 | nsec3chain->save_delete_nsec = false; |
| 3435 | |
| 3436 | /* |
| 3437 | * Log NSEC3 parameters defined by supplied NSEC3PARAM RDATA. |
| 3438 | */ |
| 3439 | if (nsec3param->flags == 0) { |
| 3440 | strlcpy(flags, "NONE" , sizeof(flags)); |
| 3441 | } else { |
| 3442 | flags[0] = '\0'; |
| 3443 | if ((nsec3param->flags & DNS_NSEC3FLAG_REMOVE) != 0) { |
| 3444 | strlcat(flags, "REMOVE" , sizeof(flags)); |
| 3445 | } |
| 3446 | if ((nsec3param->flags & DNS_NSEC3FLAG_INITIAL) != 0) { |
| 3447 | if (flags[0] == '\0') { |
| 3448 | strlcpy(flags, "INITIAL" , sizeof(flags)); |
| 3449 | } else { |
| 3450 | strlcat(flags, "|INITIAL" , sizeof(flags)); |
| 3451 | } |
| 3452 | } |
| 3453 | if ((nsec3param->flags & DNS_NSEC3FLAG_CREATE) != 0) { |
| 3454 | if (flags[0] == '\0') { |
| 3455 | strlcpy(flags, "CREATE" , sizeof(flags)); |
| 3456 | } else { |
| 3457 | strlcat(flags, "|CREATE" , sizeof(flags)); |
| 3458 | } |
| 3459 | } |
| 3460 | if ((nsec3param->flags & DNS_NSEC3FLAG_NONSEC) != 0) { |
| 3461 | if (flags[0] == '\0') { |
| 3462 | strlcpy(flags, "NONSEC" , sizeof(flags)); |
| 3463 | } else { |
| 3464 | strlcat(flags, "|NONSEC" , sizeof(flags)); |
| 3465 | } |
| 3466 | } |
| 3467 | if ((nsec3param->flags & DNS_NSEC3FLAG_OPTOUT) != 0) { |
| 3468 | if (flags[0] == '\0') { |
| 3469 | strlcpy(flags, "OPTOUT" , sizeof(flags)); |
| 3470 | } else { |
| 3471 | strlcat(flags, "|OPTOUT" , sizeof(flags)); |
| 3472 | } |
| 3473 | } |
| 3474 | } |
| 3475 | result = dns_nsec3param_salttotext(nsec3param, saltbuf, |
| 3476 | sizeof(saltbuf)); |
| 3477 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 3478 | dnssec_log(zone, ISC_LOG_INFO, "zone_addnsec3chain(%u,%s,%u,%s)" , |
| 3479 | nsec3param->hash, flags, nsec3param->iterations, saltbuf); |
| 3480 | |
| 3481 | /* |
| 3482 | * If the NSEC3 chain defined by the supplied NSEC3PARAM RDATA is |
| 3483 | * currently being processed, interrupt its processing to avoid |
| 3484 | * simultaneously adding and removing records for the same NSEC3 chain. |
| 3485 | */ |
| 3486 | for (current = ISC_LIST_HEAD(zone->nsec3chain); |
| 3487 | current != NULL; |
| 3488 | current = ISC_LIST_NEXT(current, link)) |
| 3489 | { |
| 3490 | if ((current->db == db) && |
| 3491 | (current->nsec3param.hash == nsec3param->hash) && |
| 3492 | (current->nsec3param.iterations == |
| 3493 | nsec3param->iterations) && |
| 3494 | (current->nsec3param.salt_length == |
| 3495 | nsec3param->salt_length) && |
| 3496 | memcmp(current->nsec3param.salt, nsec3param->salt, |
| 3497 | nsec3param->salt_length) == 0) |
| 3498 | { |
| 3499 | current->done = true; |
| 3500 | } |
| 3501 | } |
| 3502 | |
| 3503 | /* |
| 3504 | * Attach zone database to the structure initialized above and create |
| 3505 | * an iterator for it with appropriate options in order to avoid |
| 3506 | * creating NSEC3 records for NSEC3 records. |
| 3507 | */ |
| 3508 | dns_db_attach(db, &nsec3chain->db); |
| 3509 | if ((nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0) { |
| 3510 | options = DNS_DB_NONSEC3; |
| 3511 | } |
| 3512 | result = dns_db_createiterator(nsec3chain->db, options, |
| 3513 | &nsec3chain->dbiterator); |
| 3514 | if (result == ISC_R_SUCCESS) { |
| 3515 | result = dns_dbiterator_first(nsec3chain->dbiterator); |
| 3516 | } |
| 3517 | if (result == ISC_R_SUCCESS) { |
| 3518 | /* |
| 3519 | * Database iterator initialization succeeded. We are now |
| 3520 | * ready to kick off adding/removing records belonging to this |
| 3521 | * NSEC3 chain. Append the structure initialized above to the |
| 3522 | * "nsec3chain" list for the zone and set the appropriate zone |
| 3523 | * timer so that zone_nsec3chain() is called as soon as |
| 3524 | * possible. |
| 3525 | */ |
| 3526 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 3527 | ISC_LIST_INITANDAPPEND(zone->nsec3chain, |
| 3528 | nsec3chain, link); |
| 3529 | nsec3chain = NULL; |
| 3530 | if (isc_time_isepoch(&zone->nsec3chaintime)) { |
| 3531 | TIME_NOW(&now); |
| 3532 | zone->nsec3chaintime = now; |
| 3533 | if (zone->task != NULL) { |
| 3534 | zone_settimer(zone, &now); |
| 3535 | } |
| 3536 | } |
| 3537 | } |
| 3538 | |
| 3539 | if (nsec3chain != NULL) { |
| 3540 | if (nsec3chain->db != NULL) { |
| 3541 | dns_db_detach(&nsec3chain->db); |
| 3542 | } |
| 3543 | if (nsec3chain->dbiterator != NULL) { |
| 3544 | dns_dbiterator_destroy(&nsec3chain->dbiterator); |
| 3545 | } |
| 3546 | isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); |
| 3547 | } |
| 3548 | |
| 3549 | cleanup: |
| 3550 | if (db != NULL) { |
| 3551 | dns_db_detach(&db); |
| 3552 | } |
| 3553 | return (result); |
| 3554 | } |
| 3555 | |
| 3556 | /* |
| 3557 | * Find private-type records at the zone apex which signal that an NSEC3 chain |
| 3558 | * should be added or removed. For each such record, extract NSEC3PARAM RDATA |
| 3559 | * and pass it to zone_addnsec3chain(). |
| 3560 | * |
| 3561 | * Zone must be locked by caller. |
| 3562 | */ |
| 3563 | static void |
| 3564 | resume_addnsec3chain(dns_zone_t *zone) { |
| 3565 | dns_dbnode_t *node = NULL; |
| 3566 | dns_dbversion_t *version = NULL; |
| 3567 | dns_rdataset_t rdataset; |
| 3568 | isc_result_t result; |
| 3569 | dns_rdata_nsec3param_t nsec3param; |
| 3570 | bool nseconly = false, nsec3ok = false; |
| 3571 | dns_db_t *db = NULL; |
| 3572 | |
| 3573 | INSIST(LOCKED_ZONE(zone)); |
| 3574 | |
| 3575 | if (zone->privatetype == 0) |
| 3576 | return; |
| 3577 | |
| 3578 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 3579 | if (zone->db != NULL) { |
| 3580 | dns_db_attach(zone->db, &db); |
| 3581 | } |
| 3582 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 3583 | if (db == NULL) { |
| 3584 | goto cleanup; |
| 3585 | } |
| 3586 | |
| 3587 | result = dns_db_findnode(db, &zone->origin, false, &node); |
| 3588 | if (result != ISC_R_SUCCESS) { |
| 3589 | goto cleanup; |
| 3590 | } |
| 3591 | |
| 3592 | dns_db_currentversion(db, &version); |
| 3593 | |
| 3594 | /* |
| 3595 | * In order to create NSEC3 chains we need the DNSKEY RRset at zone |
| 3596 | * apex to exist and contain no keys using NSEC-only algorithms. |
| 3597 | */ |
| 3598 | result = dns_nsec_nseconly(db, version, &nseconly); |
| 3599 | nsec3ok = (result == ISC_R_SUCCESS && !nseconly); |
| 3600 | |
| 3601 | /* |
| 3602 | * Get the RRset containing all private-type records at the zone apex. |
| 3603 | */ |
| 3604 | dns_rdataset_init(&rdataset); |
| 3605 | result = dns_db_findrdataset(db, node, version, |
| 3606 | zone->privatetype, dns_rdatatype_none, |
| 3607 | 0, &rdataset, NULL); |
| 3608 | if (result != ISC_R_SUCCESS) { |
| 3609 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 3610 | goto cleanup; |
| 3611 | } |
| 3612 | |
| 3613 | for (result = dns_rdataset_first(&rdataset); |
| 3614 | result == ISC_R_SUCCESS; |
| 3615 | result = dns_rdataset_next(&rdataset)) |
| 3616 | { |
| 3617 | unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; |
| 3618 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3619 | dns_rdata_t private = DNS_RDATA_INIT; |
| 3620 | |
| 3621 | dns_rdataset_current(&rdataset, &private); |
| 3622 | /* |
| 3623 | * Try extracting NSEC3PARAM RDATA from this private-type |
| 3624 | * record. Failure means this private-type record does not |
| 3625 | * represent an NSEC3PARAM record, so skip it. |
| 3626 | */ |
| 3627 | if (!dns_nsec3param_fromprivate(&private, &rdata, buf, |
| 3628 | sizeof(buf))) |
| 3629 | { |
| 3630 | continue; |
| 3631 | } |
| 3632 | result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); |
| 3633 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 3634 | if (((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) || |
| 3635 | ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 && nsec3ok)) |
| 3636 | { |
| 3637 | /* |
| 3638 | * Pass the NSEC3PARAM RDATA contained in this |
| 3639 | * private-type record to zone_addnsec3chain() so that |
| 3640 | * it can kick off adding or removing NSEC3 records. |
| 3641 | */ |
| 3642 | result = zone_addnsec3chain(zone, &nsec3param); |
| 3643 | if (result != ISC_R_SUCCESS) { |
| 3644 | dnssec_log(zone, ISC_LOG_ERROR, |
| 3645 | "zone_addnsec3chain failed: %s" , |
| 3646 | dns_result_totext(result)); |
| 3647 | } |
| 3648 | } |
| 3649 | } |
| 3650 | dns_rdataset_disassociate(&rdataset); |
| 3651 | |
| 3652 | cleanup: |
| 3653 | if (db != NULL) { |
| 3654 | if (node != NULL) { |
| 3655 | dns_db_detachnode(db, &node); |
| 3656 | } |
| 3657 | if (version != NULL) { |
| 3658 | dns_db_closeversion(db, &version, false); |
| 3659 | } |
| 3660 | dns_db_detach(&db); |
| 3661 | } |
| 3662 | } |
| 3663 | |
| 3664 | static void |
| 3665 | set_resigntime(dns_zone_t *zone) { |
| 3666 | dns_rdataset_t rdataset; |
| 3667 | dns_fixedname_t fixed; |
| 3668 | unsigned int resign; |
| 3669 | isc_result_t result; |
| 3670 | uint32_t nanosecs; |
| 3671 | dns_db_t *db = NULL; |
| 3672 | |
| 3673 | /* We only re-sign zones that can be dynamically updated */ |
| 3674 | if (zone->update_disabled) |
| 3675 | return; |
| 3676 | |
| 3677 | if (!inline_secure(zone) && (zone->type != dns_zone_master || |
| 3678 | (zone->ssutable == NULL && |
| 3679 | (zone->update_acl == NULL || dns_acl_isnone(zone->update_acl))))) |
| 3680 | return; |
| 3681 | |
| 3682 | dns_rdataset_init(&rdataset); |
| 3683 | dns_fixedname_init(&fixed); |
| 3684 | |
| 3685 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 3686 | if (zone->db != NULL) |
| 3687 | dns_db_attach(zone->db, &db); |
| 3688 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 3689 | if (db == NULL) { |
| 3690 | isc_time_settoepoch(&zone->resigntime); |
| 3691 | return; |
| 3692 | } |
| 3693 | |
| 3694 | result = dns_db_getsigningtime(db, &rdataset, |
| 3695 | dns_fixedname_name(&fixed)); |
| 3696 | if (result != ISC_R_SUCCESS) { |
| 3697 | isc_time_settoepoch(&zone->resigntime); |
| 3698 | goto cleanup; |
| 3699 | } |
| 3700 | |
| 3701 | resign = rdataset.resign - zone->sigresigninginterval; |
| 3702 | dns_rdataset_disassociate(&rdataset); |
| 3703 | nanosecs = isc_random_uniform(1000000000); |
| 3704 | isc_time_set(&zone->resigntime, resign, nanosecs); |
| 3705 | cleanup: |
| 3706 | dns_db_detach(&db); |
| 3707 | return; |
| 3708 | } |
| 3709 | |
| 3710 | static isc_result_t |
| 3711 | check_nsec3param(dns_zone_t *zone, dns_db_t *db) { |
| 3712 | dns_dbnode_t *node = NULL; |
| 3713 | dns_rdataset_t rdataset; |
| 3714 | dns_dbversion_t *version = NULL; |
| 3715 | dns_rdata_nsec3param_t nsec3param; |
| 3716 | bool ok = false; |
| 3717 | isc_result_t result; |
| 3718 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3719 | bool dynamic = (zone->type == dns_zone_master) |
| 3720 | ? dns_zone_isdynamic(zone, false) : false; |
| 3721 | |
| 3722 | dns_rdataset_init(&rdataset); |
| 3723 | result = dns_db_findnode(db, &zone->origin, false, &node); |
| 3724 | if (result != ISC_R_SUCCESS) { |
| 3725 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 3726 | "nsec3param lookup failure: %s" , |
| 3727 | dns_result_totext(result)); |
| 3728 | return (result); |
| 3729 | } |
| 3730 | dns_db_currentversion(db, &version); |
| 3731 | |
| 3732 | result = dns_db_findrdataset(db, node, version, |
| 3733 | dns_rdatatype_nsec3param, |
| 3734 | dns_rdatatype_none, 0, &rdataset, NULL); |
| 3735 | if (result == ISC_R_NOTFOUND) { |
| 3736 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 3737 | result = ISC_R_SUCCESS; |
| 3738 | goto cleanup; |
| 3739 | } |
| 3740 | if (result != ISC_R_SUCCESS) { |
| 3741 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 3742 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 3743 | "nsec3param lookup failure: %s" , |
| 3744 | dns_result_totext(result)); |
| 3745 | goto cleanup; |
| 3746 | } |
| 3747 | |
| 3748 | /* |
| 3749 | * For dynamic zones we must support every algorithm so we can |
| 3750 | * regenerate all the NSEC3 chains. |
| 3751 | * For non-dynamic zones we only need to find a supported algorithm. |
| 3752 | */ |
| 3753 | for (result = dns_rdataset_first(&rdataset); |
| 3754 | result == ISC_R_SUCCESS; |
| 3755 | result = dns_rdataset_next(&rdataset)) |
| 3756 | { |
| 3757 | dns_rdataset_current(&rdataset, &rdata); |
| 3758 | result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); |
| 3759 | dns_rdata_reset(&rdata); |
| 3760 | INSIST(result == ISC_R_SUCCESS); |
| 3761 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NSEC3TESTZONE) && |
| 3762 | nsec3param.hash == DNS_NSEC3_UNKNOWNALG && !dynamic) |
| 3763 | { |
| 3764 | dns_zone_log(zone, ISC_LOG_WARNING, |
| 3765 | "nsec3 test \"unknown\" hash algorithm found: %u" , |
| 3766 | nsec3param.hash); |
| 3767 | ok = true; |
| 3768 | } else if (!dns_nsec3_supportedhash(nsec3param.hash)) { |
| 3769 | if (dynamic) { |
| 3770 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 3771 | "unsupported nsec3 hash algorithm" |
| 3772 | " in dynamic zone: %u" , |
| 3773 | nsec3param.hash); |
| 3774 | result = DNS_R_BADZONE; |
| 3775 | /* Stop second error message. */ |
| 3776 | ok = true; |
| 3777 | break; |
| 3778 | } else |
| 3779 | dns_zone_log(zone, ISC_LOG_WARNING, |
| 3780 | "unsupported nsec3 hash algorithm: %u" , |
| 3781 | nsec3param.hash); |
| 3782 | } else { |
| 3783 | ok = true; |
| 3784 | } |
| 3785 | } |
| 3786 | if (result == ISC_R_NOMORE) { |
| 3787 | result = ISC_R_SUCCESS; |
| 3788 | } |
| 3789 | |
| 3790 | if (!ok) { |
| 3791 | result = DNS_R_BADZONE; |
| 3792 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 3793 | "no supported nsec3 hash algorithm" ); |
| 3794 | } |
| 3795 | |
| 3796 | cleanup: |
| 3797 | if (dns_rdataset_isassociated(&rdataset)) { |
| 3798 | dns_rdataset_disassociate(&rdataset); |
| 3799 | } |
| 3800 | dns_db_closeversion(db, &version, false); |
| 3801 | dns_db_detachnode(db, &node); |
| 3802 | return (result); |
| 3803 | } |
| 3804 | |
| 3805 | /* |
| 3806 | * Set the timer for refreshing the key zone to the soonest future time |
| 3807 | * of the set (current timer, keydata->refresh, keydata->addhd, |
| 3808 | * keydata->removehd). |
| 3809 | */ |
| 3810 | static void |
| 3811 | set_refreshkeytimer(dns_zone_t *zone, dns_rdata_keydata_t *key, |
| 3812 | isc_stdtime_t now, bool force) |
| 3813 | { |
| 3814 | const char me[] = "set_refreshkeytimer" ; |
| 3815 | isc_stdtime_t then; |
| 3816 | isc_time_t timenow, timethen; |
| 3817 | char timebuf[80]; |
| 3818 | |
| 3819 | ENTER; |
| 3820 | then = key->refresh; |
| 3821 | if (force) |
| 3822 | then = now; |
| 3823 | if (key->addhd > now && key->addhd < then) |
| 3824 | then = key->addhd; |
| 3825 | if (key->removehd > now && key->removehd < then) |
| 3826 | then = key->removehd; |
| 3827 | |
| 3828 | TIME_NOW(&timenow); |
| 3829 | if (then > now) |
| 3830 | DNS_ZONE_TIME_ADD(&timenow, then - now, &timethen); |
| 3831 | else |
| 3832 | timethen = timenow; |
| 3833 | if (isc_time_compare(&zone->refreshkeytime, &timenow) < 0 || |
| 3834 | isc_time_compare(&timethen, &zone->refreshkeytime) < 0) |
| 3835 | zone->refreshkeytime = timethen; |
| 3836 | |
| 3837 | isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80); |
| 3838 | dns_zone_log(zone, ISC_LOG_DEBUG(1), "next key refresh: %s" , timebuf); |
| 3839 | zone_settimer(zone, &timenow); |
| 3840 | } |
| 3841 | |
| 3842 | /* |
| 3843 | * Convert key(s) linked from 'keynode' to KEYDATA and add to the key zone. |
| 3844 | * If the key zone is changed, set '*changed' to true. |
| 3845 | */ |
| 3846 | static isc_result_t |
| 3847 | create_keydata(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
| 3848 | dns_diff_t *diff, dns_keytable_t *keytable, |
| 3849 | dns_keynode_t **keynodep, bool *changed) |
| 3850 | { |
| 3851 | const char me[] = "create_keydata" ; |
| 3852 | isc_result_t result = ISC_R_SUCCESS; |
| 3853 | isc_buffer_t keyb, dstb; |
| 3854 | unsigned char key_buf[4096], dst_buf[DST_KEY_MAXSIZE]; |
| 3855 | dns_rdata_keydata_t keydata; |
| 3856 | dns_rdata_dnskey_t dnskey; |
| 3857 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3858 | dns_keynode_t *keynode; |
| 3859 | isc_stdtime_t now; |
| 3860 | isc_region_t r; |
| 3861 | dst_key_t *key; |
| 3862 | |
| 3863 | REQUIRE(keynodep != NULL); |
| 3864 | keynode = *keynodep; |
| 3865 | |
| 3866 | ENTER; |
| 3867 | isc_stdtime_get(&now); |
| 3868 | |
| 3869 | /* Loop in case there's more than one key. */ |
| 3870 | while (result == ISC_R_SUCCESS) { |
| 3871 | dns_keynode_t *nextnode = NULL; |
| 3872 | |
| 3873 | key = dns_keynode_key(keynode); |
| 3874 | if (key == NULL) |
| 3875 | goto skip; |
| 3876 | |
| 3877 | isc_buffer_init(&dstb, dst_buf, sizeof(dst_buf)); |
| 3878 | CHECK(dst_key_todns(key, &dstb)); |
| 3879 | |
| 3880 | /* Convert DST key to DNSKEY. */ |
| 3881 | dns_rdata_reset(&rdata); |
| 3882 | isc_buffer_usedregion(&dstb, &r); |
| 3883 | dns_rdata_fromregion(&rdata, dst_key_class(key), |
| 3884 | dns_rdatatype_dnskey, &r); |
| 3885 | |
| 3886 | /* DSTKEY to KEYDATA. */ |
| 3887 | CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL)); |
| 3888 | CHECK(dns_keydata_fromdnskey(&keydata, &dnskey, now, 0, 0, |
| 3889 | NULL)); |
| 3890 | |
| 3891 | /* KEYDATA to rdata. */ |
| 3892 | dns_rdata_reset(&rdata); |
| 3893 | isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); |
| 3894 | CHECK(dns_rdata_fromstruct(&rdata, |
| 3895 | zone->rdclass, dns_rdatatype_keydata, |
| 3896 | &keydata, &keyb)); |
| 3897 | |
| 3898 | /* Add rdata to zone. */ |
| 3899 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, |
| 3900 | dst_key_name(key), 0, &rdata)); |
| 3901 | *changed = true; |
| 3902 | |
| 3903 | /* Refresh new keys from the zone apex as soon as possible. */ |
| 3904 | set_refreshkeytimer(zone, &keydata, now, true); |
| 3905 | |
| 3906 | skip: |
| 3907 | result = dns_keytable_nextkeynode(keytable, keynode, &nextnode); |
| 3908 | if (result != ISC_R_NOTFOUND) { |
| 3909 | dns_keytable_detachkeynode(keytable, &keynode); |
| 3910 | keynode = nextnode; |
| 3911 | } |
| 3912 | } |
| 3913 | |
| 3914 | if (keynode != NULL) |
| 3915 | dns_keytable_detachkeynode(keytable, &keynode); |
| 3916 | *keynodep = NULL; |
| 3917 | |
| 3918 | return (ISC_R_SUCCESS); |
| 3919 | |
| 3920 | failure: |
| 3921 | return (result); |
| 3922 | } |
| 3923 | |
| 3924 | /* |
| 3925 | * Remove from the key zone all the KEYDATA records found in rdataset. |
| 3926 | */ |
| 3927 | static isc_result_t |
| 3928 | delete_keydata(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, |
| 3929 | dns_name_t *name, dns_rdataset_t *rdataset) |
| 3930 | { |
| 3931 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3932 | isc_result_t result, uresult; |
| 3933 | |
| 3934 | for (result = dns_rdataset_first(rdataset); |
| 3935 | result == ISC_R_SUCCESS; |
| 3936 | result = dns_rdataset_next(rdataset)) { |
| 3937 | dns_rdata_reset(&rdata); |
| 3938 | dns_rdataset_current(rdataset, &rdata); |
| 3939 | uresult = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, |
| 3940 | name, 0, &rdata); |
| 3941 | if (uresult != ISC_R_SUCCESS) |
| 3942 | return (uresult); |
| 3943 | } |
| 3944 | if (result == ISC_R_NOMORE) |
| 3945 | result = ISC_R_SUCCESS; |
| 3946 | return (result); |
| 3947 | } |
| 3948 | |
| 3949 | /* |
| 3950 | * Compute the DNSSEC key ID for a DNSKEY record. |
| 3951 | */ |
| 3952 | static isc_result_t |
| 3953 | compute_tag(dns_name_t *name, dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx, |
| 3954 | dns_keytag_t *tag) |
| 3955 | { |
| 3956 | isc_result_t result; |
| 3957 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3958 | unsigned char data[4096]; |
| 3959 | isc_buffer_t buffer; |
| 3960 | dst_key_t *dstkey = NULL; |
| 3961 | |
| 3962 | isc_buffer_init(&buffer, data, sizeof(data)); |
| 3963 | dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, |
| 3964 | dns_rdatatype_dnskey, dnskey, &buffer); |
| 3965 | |
| 3966 | result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &dstkey); |
| 3967 | if (result == ISC_R_SUCCESS) { |
| 3968 | *tag = dst_key_id(dstkey); |
| 3969 | dst_key_free(&dstkey); |
| 3970 | } |
| 3971 | |
| 3972 | return (result); |
| 3973 | } |
| 3974 | |
| 3975 | /* |
| 3976 | * Add key to the security roots. |
| 3977 | */ |
| 3978 | static void |
| 3979 | trust_key(dns_zone_t *zone, dns_name_t *keyname, |
| 3980 | dns_rdata_dnskey_t *dnskey, bool initial, |
| 3981 | isc_mem_t *mctx) |
| 3982 | { |
| 3983 | isc_result_t result; |
| 3984 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 3985 | unsigned char data[4096]; |
| 3986 | isc_buffer_t buffer; |
| 3987 | dns_keytable_t *sr = NULL; |
| 3988 | dst_key_t *dstkey = NULL; |
| 3989 | |
| 3990 | /* Convert dnskey to DST key. */ |
| 3991 | isc_buffer_init(&buffer, data, sizeof(data)); |
| 3992 | dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, |
| 3993 | dns_rdatatype_dnskey, dnskey, &buffer); |
| 3994 | |
| 3995 | result = dns_view_getsecroots(zone->view, &sr); |
| 3996 | if (result != ISC_R_SUCCESS) |
| 3997 | goto failure; |
| 3998 | |
| 3999 | CHECK(dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &dstkey)); |
| 4000 | CHECK(dns_keytable_add(sr, true, initial, &dstkey)); |
| 4001 | dns_keytable_detach(&sr); |
| 4002 | |
| 4003 | failure: |
| 4004 | if (dstkey != NULL) |
| 4005 | dst_key_free(&dstkey); |
| 4006 | if (sr != NULL) |
| 4007 | dns_keytable_detach(&sr); |
| 4008 | return; |
| 4009 | } |
| 4010 | |
| 4011 | /* |
| 4012 | * Add a null key to the security roots for so that all queries |
| 4013 | * to the zone will fail. |
| 4014 | */ |
| 4015 | static void |
| 4016 | fail_secure(dns_zone_t *zone, dns_name_t *keyname) { |
| 4017 | isc_result_t result; |
| 4018 | dns_keytable_t *sr = NULL; |
| 4019 | |
| 4020 | result = dns_view_getsecroots(zone->view, &sr); |
| 4021 | if (result == ISC_R_SUCCESS) { |
| 4022 | dns_keytable_marksecure(sr, keyname); |
| 4023 | dns_keytable_detach(&sr); |
| 4024 | } |
| 4025 | } |
| 4026 | |
| 4027 | /* |
| 4028 | * Scan a set of KEYDATA records from the key zone. The ones that are |
| 4029 | * valid (i.e., the add holddown timer has expired) become trusted keys. |
| 4030 | */ |
| 4031 | static void |
| 4032 | load_secroots(dns_zone_t *zone, dns_name_t *name, dns_rdataset_t *rdataset) { |
| 4033 | isc_result_t result; |
| 4034 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 4035 | dns_rdata_keydata_t keydata; |
| 4036 | dns_rdata_dnskey_t dnskey; |
| 4037 | isc_mem_t *mctx = zone->mctx; |
| 4038 | int trusted = 0, revoked = 0, pending = 0; |
| 4039 | isc_stdtime_t now; |
| 4040 | dns_keytable_t *sr = NULL; |
| 4041 | |
| 4042 | isc_stdtime_get(&now); |
| 4043 | |
| 4044 | result = dns_view_getsecroots(zone->view, &sr); |
| 4045 | if (result == ISC_R_SUCCESS) { |
| 4046 | dns_keytable_delete(sr, name); |
| 4047 | dns_keytable_detach(&sr); |
| 4048 | } |
| 4049 | |
| 4050 | /* Now insert all the accepted trust anchors from this keydata set. */ |
| 4051 | for (result = dns_rdataset_first(rdataset); |
| 4052 | result == ISC_R_SUCCESS; |
| 4053 | result = dns_rdataset_next(rdataset)) |
| 4054 | { |
| 4055 | dns_rdata_reset(&rdata); |
| 4056 | dns_rdataset_current(rdataset, &rdata); |
| 4057 | |
| 4058 | /* Convert rdata to keydata. */ |
| 4059 | result = dns_rdata_tostruct(&rdata, &keydata, NULL); |
| 4060 | if (result == ISC_R_UNEXPECTEDEND) { |
| 4061 | continue; |
| 4062 | } |
| 4063 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 4064 | |
| 4065 | /* Set the key refresh timer to force a fast refresh. */ |
| 4066 | set_refreshkeytimer(zone, &keydata, now, true); |
| 4067 | |
| 4068 | /* If the removal timer is nonzero, this key was revoked. */ |
| 4069 | if (keydata.removehd != 0) { |
| 4070 | revoked++; |
| 4071 | continue; |
| 4072 | } |
| 4073 | |
| 4074 | /* |
| 4075 | * If the add timer is still pending, this key is not |
| 4076 | * trusted yet. |
| 4077 | */ |
| 4078 | if (now < keydata.addhd) { |
| 4079 | pending++; |
| 4080 | continue; |
| 4081 | } |
| 4082 | |
| 4083 | /* Convert keydata to dnskey. */ |
| 4084 | dns_keydata_todnskey(&keydata, &dnskey, NULL); |
| 4085 | |
| 4086 | /* Add to keytables. */ |
| 4087 | trusted++; |
| 4088 | trust_key(zone, name, &dnskey, (keydata.addhd == 0), mctx); |
| 4089 | } |
| 4090 | |
| 4091 | if (trusted == 0 && pending != 0) { |
| 4092 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 4093 | dns_name_format(name, namebuf, sizeof namebuf); |
| 4094 | dnssec_log(zone, ISC_LOG_ERROR, |
| 4095 | "No valid trust anchors for '%s'!" , namebuf); |
| 4096 | dnssec_log(zone, ISC_LOG_ERROR, |
| 4097 | "%d key(s) revoked, %d still pending" , |
| 4098 | revoked, pending); |
| 4099 | dnssec_log(zone, ISC_LOG_ERROR, |
| 4100 | "All queries to '%s' will fail" , namebuf); |
| 4101 | fail_secure(zone, name); |
| 4102 | } |
| 4103 | } |
| 4104 | |
| 4105 | static isc_result_t |
| 4106 | do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, |
| 4107 | dns_diff_t *diff) |
| 4108 | { |
| 4109 | dns_diff_t temp_diff; |
| 4110 | isc_result_t result; |
| 4111 | |
| 4112 | /* |
| 4113 | * Create a singleton diff. |
| 4114 | */ |
| 4115 | dns_diff_init(diff->mctx, &temp_diff); |
| 4116 | ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); |
| 4117 | |
| 4118 | /* |
| 4119 | * Apply it to the database. |
| 4120 | */ |
| 4121 | result = dns_diff_apply(&temp_diff, db, ver); |
| 4122 | ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); |
| 4123 | if (result != ISC_R_SUCCESS) { |
| 4124 | dns_difftuple_free(tuple); |
| 4125 | return (result); |
| 4126 | } |
| 4127 | |
| 4128 | /* |
| 4129 | * Merge it into the current pending journal entry. |
| 4130 | */ |
| 4131 | dns_diff_appendminimal(diff, tuple); |
| 4132 | |
| 4133 | /* |
| 4134 | * Do not clear temp_diff. |
| 4135 | */ |
| 4136 | return (ISC_R_SUCCESS); |
| 4137 | } |
| 4138 | |
| 4139 | static isc_result_t |
| 4140 | update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, |
| 4141 | dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, |
| 4142 | dns_rdata_t *rdata) |
| 4143 | { |
| 4144 | dns_difftuple_t *tuple = NULL; |
| 4145 | isc_result_t result; |
| 4146 | result = dns_difftuple_create(diff->mctx, op, |
| 4147 | name, ttl, rdata, &tuple); |
| 4148 | if (result != ISC_R_SUCCESS) |
| 4149 | return (result); |
| 4150 | return (do_one_tuple(&tuple, db, ver, diff)); |
| 4151 | } |
| 4152 | |
| 4153 | static isc_result_t |
| 4154 | update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, |
| 4155 | isc_mem_t *mctx, dns_updatemethod_t method) { |
| 4156 | dns_difftuple_t *deltuple = NULL; |
| 4157 | dns_difftuple_t *addtuple = NULL; |
| 4158 | uint32_t serial; |
| 4159 | isc_result_t result; |
| 4160 | |
| 4161 | INSIST(method != dns_updatemethod_none); |
| 4162 | |
| 4163 | CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); |
| 4164 | CHECK(dns_difftuple_copy(deltuple, &addtuple)); |
| 4165 | addtuple->op = DNS_DIFFOP_ADD; |
| 4166 | |
| 4167 | serial = dns_soa_getserial(&addtuple->rdata); |
| 4168 | serial = dns_update_soaserial(serial, method); |
| 4169 | dns_soa_setserial(serial, &addtuple->rdata); |
| 4170 | CHECK(do_one_tuple(&deltuple, db, ver, diff)); |
| 4171 | CHECK(do_one_tuple(&addtuple, db, ver, diff)); |
| 4172 | result = ISC_R_SUCCESS; |
| 4173 | |
| 4174 | failure: |
| 4175 | if (addtuple != NULL) |
| 4176 | dns_difftuple_free(&addtuple); |
| 4177 | if (deltuple != NULL) |
| 4178 | dns_difftuple_free(&deltuple); |
| 4179 | return (result); |
| 4180 | } |
| 4181 | |
| 4182 | /* |
| 4183 | * Write all transactions in 'diff' to the zone journal file. |
| 4184 | */ |
| 4185 | static isc_result_t |
| 4186 | zone_journal(dns_zone_t *zone, dns_diff_t *diff, uint32_t *sourceserial, |
| 4187 | const char *caller) |
| 4188 | { |
| 4189 | const char me[] = "zone_journal" ; |
| 4190 | const char *journalfile; |
| 4191 | isc_result_t result = ISC_R_SUCCESS; |
| 4192 | dns_journal_t *journal = NULL; |
| 4193 | unsigned int mode = DNS_JOURNAL_CREATE|DNS_JOURNAL_WRITE; |
| 4194 | |
| 4195 | ENTER; |
| 4196 | journalfile = dns_zone_getjournal(zone); |
| 4197 | if (journalfile != NULL) { |
| 4198 | result = dns_journal_open(zone->mctx, journalfile, mode, |
| 4199 | &journal); |
| 4200 | if (result != ISC_R_SUCCESS) { |
| 4201 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 4202 | "%s:dns_journal_open -> %s" , |
| 4203 | caller, dns_result_totext(result)); |
| 4204 | return (result); |
| 4205 | } |
| 4206 | |
| 4207 | if (sourceserial != NULL) |
| 4208 | dns_journal_set_sourceserial(journal, *sourceserial); |
| 4209 | |
| 4210 | result = dns_journal_write_transaction(journal, diff); |
| 4211 | if (result != ISC_R_SUCCESS) { |
| 4212 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 4213 | "%s:dns_journal_write_transaction -> %s" , |
| 4214 | caller, dns_result_totext(result)); |
| 4215 | } |
| 4216 | dns_journal_destroy(&journal); |
| 4217 | } |
| 4218 | |
| 4219 | return (result); |
| 4220 | } |
| 4221 | |
| 4222 | /* |
| 4223 | * Create an SOA record for a newly-created zone |
| 4224 | */ |
| 4225 | static isc_result_t |
| 4226 | add_soa(dns_zone_t *zone, dns_db_t *db) { |
| 4227 | isc_result_t result; |
| 4228 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 4229 | unsigned char buf[DNS_SOA_BUFFERSIZE]; |
| 4230 | dns_dbversion_t *ver = NULL; |
| 4231 | dns_diff_t diff; |
| 4232 | |
| 4233 | dns_zone_log(zone, ISC_LOG_DEBUG(1), "creating SOA" ); |
| 4234 | |
| 4235 | dns_diff_init(zone->mctx, &diff); |
| 4236 | result = dns_db_newversion(db, &ver); |
| 4237 | if (result != ISC_R_SUCCESS) { |
| 4238 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 4239 | "add_soa:dns_db_newversion -> %s" , |
| 4240 | dns_result_totext(result)); |
| 4241 | goto failure; |
| 4242 | } |
| 4243 | |
| 4244 | /* Build SOA record */ |
| 4245 | result = dns_soa_buildrdata(&zone->origin, dns_rootname, zone->rdclass, |
| 4246 | 0, 0, 0, 0, 0, buf, &rdata); |
| 4247 | if (result != ISC_R_SUCCESS) { |
| 4248 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 4249 | "add_soa:dns_soa_buildrdata -> %s" , |
| 4250 | dns_result_totext(result)); |
| 4251 | goto failure; |
| 4252 | } |
| 4253 | |
| 4254 | result = update_one_rr(db, ver, &diff, DNS_DIFFOP_ADD, |
| 4255 | &zone->origin, 0, &rdata); |
| 4256 | |
| 4257 | failure: |
| 4258 | dns_diff_clear(&diff); |
| 4259 | if (ver != NULL) |
| 4260 | dns_db_closeversion(db, &ver, (result == ISC_R_SUCCESS)); |
| 4261 | |
| 4262 | INSIST(ver == NULL); |
| 4263 | |
| 4264 | return (result); |
| 4265 | } |
| 4266 | |
| 4267 | struct addifmissing_arg { |
| 4268 | dns_db_t *db; |
| 4269 | dns_dbversion_t *ver; |
| 4270 | dns_diff_t *diff; |
| 4271 | dns_zone_t *zone; |
| 4272 | bool *changed; |
| 4273 | isc_result_t result; |
| 4274 | }; |
| 4275 | |
| 4276 | static void |
| 4277 | addifmissing(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) { |
| 4278 | dns_db_t *db = ((struct addifmissing_arg *)arg)->db; |
| 4279 | dns_dbversion_t *ver = ((struct addifmissing_arg *)arg)->ver; |
| 4280 | dns_diff_t *diff = ((struct addifmissing_arg *)arg)->diff; |
| 4281 | dns_zone_t *zone = ((struct addifmissing_arg *)arg)->zone; |
| 4282 | bool *changed = ((struct addifmissing_arg *)arg)->changed; |
| 4283 | isc_result_t result; |
| 4284 | dns_keynode_t *dummy = NULL; |
| 4285 | |
| 4286 | if (((struct addifmissing_arg *)arg)->result != ISC_R_SUCCESS) |
| 4287 | return; |
| 4288 | |
| 4289 | if (dns_keynode_managed(keynode)) { |
| 4290 | dns_fixedname_t fname; |
| 4291 | dns_name_t *keyname; |
| 4292 | dst_key_t *key; |
| 4293 | |
| 4294 | key = dns_keynode_key(keynode); |
| 4295 | if (key == NULL) |
| 4296 | return; |
| 4297 | dns_fixedname_init(&fname); |
| 4298 | |
| 4299 | keyname = dst_key_name(key); |
| 4300 | result = dns_db_find(db, keyname, ver, |
| 4301 | dns_rdatatype_keydata, |
| 4302 | DNS_DBFIND_NOWILD, 0, NULL, |
| 4303 | dns_fixedname_name(&fname), |
| 4304 | NULL, NULL); |
| 4305 | if (result == ISC_R_SUCCESS) |
| 4306 | return; |
| 4307 | dns_keytable_attachkeynode(keytable, keynode, &dummy); |
| 4308 | result = create_keydata(zone, db, ver, diff, keytable, |
| 4309 | &dummy, changed); |
| 4310 | if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) |
| 4311 | ((struct addifmissing_arg *)arg)->result = result; |
| 4312 | } |
| 4313 | }; |
| 4314 | |
| 4315 | /* |
| 4316 | * Synchronize the set of initializing keys found in managed-keys {} |
| 4317 | * statements with the set of trust anchors found in the managed-keys.bind |
| 4318 | * zone. If a domain is no longer named in managed-keys, delete all keys |
| 4319 | * from that domain from the key zone. If a domain is mentioned in in |
| 4320 | * managed-keys but there are no references to it in the key zone, load |
| 4321 | * the key zone with the initializing key(s) for that domain. |
| 4322 | */ |
| 4323 | static isc_result_t |
| 4324 | sync_keyzone(dns_zone_t *zone, dns_db_t *db) { |
| 4325 | isc_result_t result = ISC_R_SUCCESS; |
| 4326 | bool changed = false; |
| 4327 | bool commit = false; |
| 4328 | dns_keynode_t *keynode = NULL; |
| 4329 | dns_view_t *view = zone->view; |
| 4330 | dns_keytable_t *sr = NULL; |
| 4331 | dns_dbversion_t *ver = NULL; |
| 4332 | dns_diff_t diff; |
| 4333 | dns_rriterator_t rrit; |
| 4334 | struct addifmissing_arg arg; |
| 4335 | |
| 4336 | dns_zone_log(zone, ISC_LOG_DEBUG(1), "synchronizing trusted keys" ); |
| 4337 | |
| 4338 | dns_diff_init(zone->mctx, &diff); |
| 4339 | |
| 4340 | CHECK(dns_view_getsecroots(view, &sr)); |
| 4341 | |
| 4342 | result = dns_db_newversion(db, &ver); |
| 4343 | if (result != ISC_R_SUCCESS) { |
| 4344 | dnssec_log(zone, ISC_LOG_ERROR, |
| 4345 | "sync_keyzone:dns_db_newversion -> %s" , |
| 4346 | dns_result_totext(result)); |
| 4347 | goto failure; |
| 4348 | } |
| 4349 | |
| 4350 | /* |
| 4351 | * Walk the zone DB. If we find any keys whose names are no longer |
| 4352 | * in managed-keys (or *are* in trusted-keys, meaning they are |
| 4353 | * permanent and not RFC5011-maintained), delete them from the |
| 4354 | * zone. Otherwise call load_secroots(), which loads keys into |
| 4355 | * secroots as appropriate. |
| 4356 | */ |
| 4357 | dns_rriterator_init(&rrit, db, ver, 0); |
| 4358 | for (result = dns_rriterator_first(&rrit); |
| 4359 | result == ISC_R_SUCCESS; |
| 4360 | result = dns_rriterator_nextrrset(&rrit)) |
| 4361 | { |
| 4362 | dns_rdataset_t *rdataset = NULL; |
| 4363 | dns_name_t *rrname = NULL; |
| 4364 | uint32_t ttl; |
| 4365 | |
| 4366 | dns_rriterator_current(&rrit, &rrname, &ttl, &rdataset, NULL); |
| 4367 | if (!dns_rdataset_isassociated(rdataset)) { |
| 4368 | dns_rriterator_destroy(&rrit); |
| 4369 | goto failure; |
| 4370 | } |
| 4371 | |
| 4372 | if (rdataset->type != dns_rdatatype_keydata) { |
| 4373 | continue; |
| 4374 | } |
| 4375 | |
| 4376 | result = dns_keytable_find(sr, rrname, &keynode); |
| 4377 | if ((result != ISC_R_SUCCESS && |
| 4378 | result != DNS_R_PARTIALMATCH) || |
| 4379 | dns_keynode_managed(keynode) == false) |
| 4380 | { |
| 4381 | CHECK(delete_keydata(db, ver, &diff, |
| 4382 | rrname, rdataset)); |
| 4383 | changed = true; |
| 4384 | } else { |
| 4385 | load_secroots(zone, rrname, rdataset); |
| 4386 | } |
| 4387 | |
| 4388 | if (keynode != NULL) { |
| 4389 | dns_keytable_detachkeynode(sr, &keynode); |
| 4390 | } |
| 4391 | } |
| 4392 | dns_rriterator_destroy(&rrit); |
| 4393 | |
| 4394 | /* |
| 4395 | * Now walk secroots to find any managed keys that aren't |
| 4396 | * in the zone. If we find any, we add them to the zone. |
| 4397 | */ |
| 4398 | arg.db = db; |
| 4399 | arg.ver = ver; |
| 4400 | arg.result = ISC_R_SUCCESS; |
| 4401 | arg.diff = &diff; |
| 4402 | arg.zone = zone; |
| 4403 | arg.changed = &changed; |
| 4404 | dns_keytable_forall(sr, addifmissing, &arg); |
| 4405 | result = arg.result; |
| 4406 | if (changed) { |
| 4407 | /* Write changes to journal file. */ |
| 4408 | CHECK(update_soa_serial(db, ver, &diff, zone->mctx, |
| 4409 | zone->updatemethod)); |
| 4410 | CHECK(zone_journal(zone, &diff, NULL, "sync_keyzone" )); |
| 4411 | |
| 4412 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); |
| 4413 | zone_needdump(zone, 30); |
| 4414 | commit = true; |
| 4415 | } |
| 4416 | |
| 4417 | failure: |
| 4418 | if (result != ISC_R_SUCCESS && |
| 4419 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) |
| 4420 | { |
| 4421 | dnssec_log(zone, ISC_LOG_ERROR, |
| 4422 | "unable to synchronize managed keys: %s" , |
| 4423 | dns_result_totext(result)); |
| 4424 | isc_time_settoepoch(&zone->refreshkeytime); |
| 4425 | } |
| 4426 | if (keynode != NULL) { |
| 4427 | dns_keytable_detachkeynode(sr, &keynode); |
| 4428 | } |
| 4429 | if (sr != NULL) { |
| 4430 | dns_keytable_detach(&sr); |
| 4431 | } |
| 4432 | if (ver != NULL) { |
| 4433 | dns_db_closeversion(db, &ver, commit); |
| 4434 | } |
| 4435 | dns_diff_clear(&diff); |
| 4436 | |
| 4437 | INSIST(ver == NULL); |
| 4438 | |
| 4439 | return (result); |
| 4440 | } |
| 4441 | |
| 4442 | isc_result_t |
| 4443 | dns_zone_synckeyzone(dns_zone_t *zone) { |
| 4444 | isc_result_t result; |
| 4445 | dns_db_t *db = NULL; |
| 4446 | |
| 4447 | if (zone->type != dns_zone_key) { |
| 4448 | return (DNS_R_BADZONE); |
| 4449 | } |
| 4450 | |
| 4451 | CHECK(dns_zone_getdb(zone, &db)); |
| 4452 | |
| 4453 | LOCK_ZONE(zone); |
| 4454 | result = sync_keyzone(zone, db); |
| 4455 | UNLOCK_ZONE(zone); |
| 4456 | |
| 4457 | failure: |
| 4458 | if (db != NULL) { |
| 4459 | dns_db_detach(&db); |
| 4460 | } |
| 4461 | return (result); |
| 4462 | } |
| 4463 | |
| 4464 | static void |
| 4465 | maybe_send_secure(dns_zone_t *zone) { |
| 4466 | isc_result_t result; |
| 4467 | |
| 4468 | /* |
| 4469 | * We've finished loading, or else failed to load, an inline-signing |
| 4470 | * 'secure' zone. We now need information about the status of the |
| 4471 | * 'raw' zone. If we failed to load, then we need it to send a |
| 4472 | * copy of its database; if we succeeded, we need it to send its |
| 4473 | * serial number so that we can sync with it. If it has not yet |
| 4474 | * loaded, we set a flag so that it will send the necessary |
| 4475 | * information when it has finished loading. |
| 4476 | */ |
| 4477 | if (zone->raw->db != NULL) { |
| 4478 | if (zone->db != NULL) { |
| 4479 | uint32_t serial; |
| 4480 | unsigned int soacount; |
| 4481 | |
| 4482 | result = zone_get_from_db(zone->raw, zone->raw->db, |
| 4483 | NULL, &soacount, &serial, |
| 4484 | NULL, NULL, NULL, NULL, NULL); |
| 4485 | if (result == ISC_R_SUCCESS && soacount > 0U) |
| 4486 | zone_send_secureserial(zone->raw, serial); |
| 4487 | } else |
| 4488 | zone_send_securedb(zone->raw, zone->raw->db); |
| 4489 | |
| 4490 | } else |
| 4491 | DNS_ZONE_SETFLAG(zone->raw, DNS_ZONEFLG_SENDSECURE); |
| 4492 | } |
| 4493 | |
| 4494 | static bool |
| 4495 | zone_unchanged(dns_db_t *db1, dns_db_t *db2, isc_mem_t *mctx) { |
| 4496 | isc_result_t result; |
| 4497 | bool answer = false; |
| 4498 | dns_diff_t diff; |
| 4499 | |
| 4500 | dns_diff_init(mctx, &diff); |
| 4501 | result = dns_db_diffx(&diff, db1, NULL, db2, NULL, NULL); |
| 4502 | if (result == ISC_R_SUCCESS && ISC_LIST_EMPTY(diff.tuples)) |
| 4503 | answer = true; |
| 4504 | dns_diff_clear(&diff); |
| 4505 | return (answer); |
| 4506 | } |
| 4507 | |
| 4508 | /* |
| 4509 | * The zone is presumed to be locked. |
| 4510 | * If this is a inline_raw zone the secure version is also locked. |
| 4511 | */ |
| 4512 | static isc_result_t |
| 4513 | zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, |
| 4514 | isc_result_t result) |
| 4515 | { |
| 4516 | unsigned int soacount = 0; |
| 4517 | unsigned int nscount = 0; |
| 4518 | unsigned int errors = 0; |
| 4519 | uint32_t serial, oldserial, refresh, retry, expire, minimum; |
| 4520 | isc_time_t now; |
| 4521 | bool needdump = false; |
| 4522 | bool hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE); |
| 4523 | bool nomaster = false; |
| 4524 | bool had_db = false; |
| 4525 | unsigned int options; |
| 4526 | dns_include_t *inc; |
| 4527 | |
| 4528 | INSIST(LOCKED_ZONE(zone)); |
| 4529 | if (inline_raw(zone)) { |
| 4530 | INSIST(LOCKED_ZONE(zone->secure)); |
| 4531 | } |
| 4532 | |
| 4533 | TIME_NOW(&now); |
| 4534 | |
| 4535 | /* |
| 4536 | * Initiate zone transfer? We may need a error code that |
| 4537 | * indicates that the "permanent" form does not exist. |
| 4538 | * XXX better error feedback to log. |
| 4539 | */ |
| 4540 | if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { |
| 4541 | if (zone->type == dns_zone_slave || |
| 4542 | zone->type == dns_zone_mirror || |
| 4543 | zone->type == dns_zone_stub || |
| 4544 | (zone->type == dns_zone_redirect && |
| 4545 | zone->masters == NULL)) |
| 4546 | { |
| 4547 | if (result == ISC_R_FILENOTFOUND) { |
| 4548 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4549 | ISC_LOG_DEBUG(1), |
| 4550 | "no master file" ); |
| 4551 | } else if (result != DNS_R_NOMASTERFILE) { |
| 4552 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4553 | ISC_LOG_ERROR, |
| 4554 | "loading from master file %s " |
| 4555 | "failed: %s" , |
| 4556 | zone->masterfile, |
| 4557 | dns_result_totext(result)); |
| 4558 | } |
| 4559 | } else if (zone->type == dns_zone_master && |
| 4560 | inline_secure(zone) && result == ISC_R_FILENOTFOUND) |
| 4561 | { |
| 4562 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4563 | ISC_LOG_DEBUG(1), |
| 4564 | "no master file, requesting db" ); |
| 4565 | maybe_send_secure(zone); |
| 4566 | } else { |
| 4567 | int level = ISC_LOG_ERROR; |
| 4568 | if (zone->type == dns_zone_key && |
| 4569 | result == ISC_R_FILENOTFOUND) |
| 4570 | level = ISC_LOG_DEBUG(1); |
| 4571 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, level, |
| 4572 | "loading from master file %s failed: %s" , |
| 4573 | zone->masterfile, |
| 4574 | dns_result_totext(result)); |
| 4575 | nomaster = true; |
| 4576 | } |
| 4577 | |
| 4578 | if (zone->type != dns_zone_key) { |
| 4579 | goto cleanup; |
| 4580 | } |
| 4581 | } |
| 4582 | |
| 4583 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(2), |
| 4584 | "number of nodes in database: %u" , |
| 4585 | dns_db_nodecount(db)); |
| 4586 | |
| 4587 | if (result == DNS_R_SEENINCLUDE) { |
| 4588 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HASINCLUDE); |
| 4589 | } else { |
| 4590 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HASINCLUDE); |
| 4591 | } |
| 4592 | |
| 4593 | /* |
| 4594 | * If there's no master file for a key zone, then the zone is new: |
| 4595 | * create an SOA record. (We do this now, instead of later, so that |
| 4596 | * if there happens to be a journal file, we can roll forward from |
| 4597 | * a sane starting point.) |
| 4598 | */ |
| 4599 | if (nomaster && zone->type == dns_zone_key) { |
| 4600 | result = add_soa(zone, db); |
| 4601 | if (result != ISC_R_SUCCESS) { |
| 4602 | goto cleanup; |
| 4603 | } |
| 4604 | } |
| 4605 | |
| 4606 | /* |
| 4607 | * Apply update log, if any, on initial load. |
| 4608 | */ |
| 4609 | if (zone->journal != NULL && |
| 4610 | ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) && |
| 4611 | ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) |
| 4612 | { |
| 4613 | if (zone->type == dns_zone_master && (inline_secure(zone) || |
| 4614 | (zone->update_acl != NULL || zone->ssutable != NULL))) |
| 4615 | { |
| 4616 | options = DNS_JOURNALOPT_RESIGN; |
| 4617 | } else { |
| 4618 | options = 0; |
| 4619 | } |
| 4620 | result = dns_journal_rollforward(zone->mctx, db, options, |
| 4621 | zone->journal); |
| 4622 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND && |
| 4623 | result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL && |
| 4624 | result != ISC_R_RANGE) |
| 4625 | { |
| 4626 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4627 | ISC_LOG_ERROR, |
| 4628 | "journal rollforward failed: %s" , |
| 4629 | dns_result_totext(result)); |
| 4630 | goto cleanup; |
| 4631 | |
| 4632 | |
| 4633 | } |
| 4634 | if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) { |
| 4635 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4636 | ISC_LOG_ERROR, |
| 4637 | "journal rollforward failed: " |
| 4638 | "journal out of sync with zone" ); |
| 4639 | goto cleanup; |
| 4640 | } |
| 4641 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(1), |
| 4642 | "journal rollforward completed " |
| 4643 | "successfully: %s" , |
| 4644 | dns_result_totext(result)); |
| 4645 | if (result == ISC_R_SUCCESS) { |
| 4646 | needdump = true; |
| 4647 | } |
| 4648 | } |
| 4649 | |
| 4650 | /* |
| 4651 | * Obtain ns, soa and cname counts for top of zone. |
| 4652 | */ |
| 4653 | INSIST(db != NULL); |
| 4654 | result = zone_get_from_db(zone, db, &nscount, &soacount, &serial, |
| 4655 | &refresh, &retry, &expire, &minimum, |
| 4656 | &errors); |
| 4657 | if (result != ISC_R_SUCCESS && zone->type != dns_zone_key) { |
| 4658 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_ERROR, |
| 4659 | "could not find NS and/or SOA records" ); |
| 4660 | } |
| 4661 | |
| 4662 | /* |
| 4663 | * Check to make sure the journal is up to date, and remove the |
| 4664 | * journal file if it isn't, as we wouldn't be able to apply |
| 4665 | * updates otherwise. |
| 4666 | */ |
| 4667 | if (zone->journal != NULL && dns_zone_isdynamic(zone, true) && |
| 4668 | ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) |
| 4669 | { |
| 4670 | uint32_t jserial; |
| 4671 | dns_journal_t *journal = NULL; |
| 4672 | bool empty = false; |
| 4673 | |
| 4674 | result = dns_journal_open(zone->mctx, zone->journal, |
| 4675 | DNS_JOURNAL_READ, &journal); |
| 4676 | if (result == ISC_R_SUCCESS) { |
| 4677 | jserial = dns_journal_last_serial(journal); |
| 4678 | empty = dns_journal_empty(journal); |
| 4679 | dns_journal_destroy(&journal); |
| 4680 | } else { |
| 4681 | jserial = serial; |
| 4682 | result = ISC_R_SUCCESS; |
| 4683 | } |
| 4684 | |
| 4685 | if (jserial != serial) { |
| 4686 | if (!empty) { |
| 4687 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4688 | ISC_LOG_INFO, |
| 4689 | "journal file is out of date: " |
| 4690 | "removing journal file" ); |
| 4691 | } |
| 4692 | if (remove(zone->journal) < 0 && errno != ENOENT) { |
| 4693 | char strbuf[ISC_STRERRORSIZE]; |
| 4694 | strerror_r(errno, strbuf, sizeof(strbuf)); |
| 4695 | isc_log_write(dns_lctx, |
| 4696 | DNS_LOGCATEGORY_GENERAL, |
| 4697 | DNS_LOGMODULE_ZONE, |
| 4698 | ISC_LOG_WARNING, |
| 4699 | "unable to remove journal " |
| 4700 | "'%s': '%s'" , |
| 4701 | zone->journal, strbuf); |
| 4702 | } |
| 4703 | } |
| 4704 | } |
| 4705 | |
| 4706 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(1), |
| 4707 | "loaded; checking validity" ); |
| 4708 | |
| 4709 | /* |
| 4710 | * Master / Slave / Mirror / Stub zones require both NS and SOA records |
| 4711 | * at the top of the zone. |
| 4712 | */ |
| 4713 | |
| 4714 | switch (zone->type) { |
| 4715 | case dns_zone_dlz: |
| 4716 | case dns_zone_master: |
| 4717 | case dns_zone_slave: |
| 4718 | case dns_zone_mirror: |
| 4719 | case dns_zone_stub: |
| 4720 | case dns_zone_redirect: |
| 4721 | if (soacount != 1) { |
| 4722 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4723 | ISC_LOG_ERROR, |
| 4724 | "has %d SOA records" , soacount); |
| 4725 | result = DNS_R_BADZONE; |
| 4726 | } |
| 4727 | if (nscount == 0) { |
| 4728 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4729 | ISC_LOG_ERROR, |
| 4730 | "has no NS records" ); |
| 4731 | result = DNS_R_BADZONE; |
| 4732 | } |
| 4733 | if (result != ISC_R_SUCCESS) { |
| 4734 | goto cleanup; |
| 4735 | } |
| 4736 | if (zone->type == dns_zone_master && errors != 0) { |
| 4737 | result = DNS_R_BADZONE; |
| 4738 | goto cleanup; |
| 4739 | } |
| 4740 | if (zone->type != dns_zone_stub && |
| 4741 | zone->type != dns_zone_redirect) |
| 4742 | { |
| 4743 | result = check_nsec3param(zone, db); |
| 4744 | if (result != ISC_R_SUCCESS) |
| 4745 | goto cleanup; |
| 4746 | } |
| 4747 | if (zone->type == dns_zone_master && |
| 4748 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKINTEGRITY) && |
| 4749 | !integrity_checks(zone, db)) |
| 4750 | { |
| 4751 | result = DNS_R_BADZONE; |
| 4752 | goto cleanup; |
| 4753 | } |
| 4754 | if (zone->type == dns_zone_master && |
| 4755 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRR) && |
| 4756 | !zone_check_dup(zone, db)) |
| 4757 | { |
| 4758 | result = DNS_R_BADZONE; |
| 4759 | goto cleanup; |
| 4760 | } |
| 4761 | |
| 4762 | result = dns_zone_verifydb(zone, db, NULL); |
| 4763 | if (result != ISC_R_SUCCESS) { |
| 4764 | goto cleanup; |
| 4765 | } |
| 4766 | |
| 4767 | if (zone->db != NULL) { |
| 4768 | unsigned int oldsoacount; |
| 4769 | |
| 4770 | /* |
| 4771 | * This is checked in zone_replacedb() for slave zones |
| 4772 | * as they don't reload from disk. |
| 4773 | */ |
| 4774 | result = zone_get_from_db(zone, zone->db, NULL, |
| 4775 | &oldsoacount, &oldserial, |
| 4776 | NULL, NULL, NULL, NULL, |
| 4777 | NULL); |
| 4778 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 4779 | RUNTIME_CHECK(soacount > 0U); |
| 4780 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && |
| 4781 | !isc_serial_gt(serial, oldserial)) { |
| 4782 | uint32_t serialmin, serialmax; |
| 4783 | |
| 4784 | INSIST(zone->type == dns_zone_master); |
| 4785 | INSIST(zone->raw == NULL); |
| 4786 | |
| 4787 | if (serial == oldserial && |
| 4788 | zone_unchanged(zone->db, db, zone->mctx)) { |
| 4789 | dns_zone_logc(zone, |
| 4790 | DNS_LOGCATEGORY_ZONELOAD, |
| 4791 | ISC_LOG_INFO, |
| 4792 | "ixfr-from-differences: " |
| 4793 | "unchanged" ); |
| 4794 | goto done; |
| 4795 | } |
| 4796 | |
| 4797 | serialmin = (oldserial + 1) & 0xffffffffU; |
| 4798 | serialmax = (oldserial + 0x7fffffffU) & |
| 4799 | 0xffffffffU; |
| 4800 | dns_zone_logc(zone, |
| 4801 | DNS_LOGCATEGORY_ZONELOAD, |
| 4802 | ISC_LOG_ERROR, |
| 4803 | "ixfr-from-differences: " |
| 4804 | "new serial (%u) out of range " |
| 4805 | "[%u - %u]" , serial, serialmin, |
| 4806 | serialmax); |
| 4807 | result = DNS_R_BADZONE; |
| 4808 | goto cleanup; |
| 4809 | } else if (!isc_serial_ge(serial, oldserial)) { |
| 4810 | dns_zone_logc(zone, |
| 4811 | DNS_LOGCATEGORY_ZONELOAD, |
| 4812 | ISC_LOG_ERROR, |
| 4813 | "zone serial (%u/%u) has gone " |
| 4814 | "backwards" , serial, oldserial); |
| 4815 | } else if (serial == oldserial && !hasinclude && |
| 4816 | strcmp(zone->db_argv[0], "_builtin" ) != 0) |
| 4817 | { |
| 4818 | dns_zone_logc(zone, |
| 4819 | DNS_LOGCATEGORY_ZONELOAD, |
| 4820 | ISC_LOG_ERROR, |
| 4821 | "zone serial (%u) unchanged. " |
| 4822 | "zone may fail to transfer " |
| 4823 | "to slaves." , serial); |
| 4824 | } |
| 4825 | } |
| 4826 | |
| 4827 | if (zone->type == dns_zone_master && |
| 4828 | (zone->update_acl != NULL || zone->ssutable != NULL) && |
| 4829 | zone->sigresigninginterval < (3 * refresh) && |
| 4830 | dns_db_issecure(db)) |
| 4831 | { |
| 4832 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 4833 | ISC_LOG_WARNING, |
| 4834 | "sig-re-signing-interval less than " |
| 4835 | "3 * refresh." ); |
| 4836 | } |
| 4837 | |
| 4838 | zone->refresh = RANGE(refresh, |
| 4839 | zone->minrefresh, zone->maxrefresh); |
| 4840 | zone->retry = RANGE(retry, |
| 4841 | zone->minretry, zone->maxretry); |
| 4842 | zone->expire = RANGE(expire, zone->refresh + zone->retry, |
| 4843 | DNS_MAX_EXPIRE); |
| 4844 | zone->minimum = minimum; |
| 4845 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); |
| 4846 | |
| 4847 | if (zone->type == dns_zone_slave || |
| 4848 | zone->type == dns_zone_mirror || |
| 4849 | zone->type == dns_zone_stub || |
| 4850 | (zone->type == dns_zone_redirect && |
| 4851 | zone->masters != NULL)) |
| 4852 | { |
| 4853 | isc_time_t t; |
| 4854 | uint32_t delay; |
| 4855 | |
| 4856 | result = isc_file_getmodtime(zone->journal, &t); |
| 4857 | if (result != ISC_R_SUCCESS) { |
| 4858 | result = isc_file_getmodtime(zone->masterfile, |
| 4859 | &t); |
| 4860 | } |
| 4861 | if (result == ISC_R_SUCCESS) { |
| 4862 | DNS_ZONE_TIME_ADD(&t, zone->expire, |
| 4863 | &zone->expiretime); |
| 4864 | } else { |
| 4865 | DNS_ZONE_TIME_ADD(&now, zone->retry, |
| 4866 | &zone->expiretime); |
| 4867 | } |
| 4868 | |
| 4869 | delay = (zone->retry - |
| 4870 | isc_random_uniform((zone->retry * 3) / 4)); |
| 4871 | DNS_ZONE_TIME_ADD(&now, delay, &zone->refreshtime); |
| 4872 | if (isc_time_compare(&zone->refreshtime, |
| 4873 | &zone->expiretime) >= 0) |
| 4874 | { |
| 4875 | zone->refreshtime = now; |
| 4876 | } |
| 4877 | } |
| 4878 | |
| 4879 | break; |
| 4880 | |
| 4881 | case dns_zone_key: |
| 4882 | result = sync_keyzone(zone, db); |
| 4883 | if (result != ISC_R_SUCCESS) { |
| 4884 | goto cleanup; |
| 4885 | } |
| 4886 | break; |
| 4887 | |
| 4888 | default: |
| 4889 | UNEXPECTED_ERROR(__FILE__, __LINE__, |
| 4890 | "unexpected zone type %d" , zone->type); |
| 4891 | result = ISC_R_UNEXPECTED; |
| 4892 | goto cleanup; |
| 4893 | } |
| 4894 | |
| 4895 | /* |
| 4896 | * Check for weak DNSKEY's. |
| 4897 | */ |
| 4898 | if (zone->type == dns_zone_master) { |
| 4899 | zone_check_dnskeys(zone, db); |
| 4900 | } |
| 4901 | |
| 4902 | /* |
| 4903 | * Schedule DNSSEC key refresh. |
| 4904 | */ |
| 4905 | if (zone->type == dns_zone_master && |
| 4906 | DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) |
| 4907 | { |
| 4908 | zone->refreshkeytime = now; |
| 4909 | } |
| 4910 | |
| 4911 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); |
| 4912 | if (zone->db != NULL) { |
| 4913 | had_db = true; |
| 4914 | result = zone_replacedb(zone, db, false); |
| 4915 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
| 4916 | if (result != ISC_R_SUCCESS) { |
| 4917 | goto cleanup; |
| 4918 | } |
| 4919 | } else { |
| 4920 | zone_attachdb(zone, db); |
| 4921 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
| 4922 | DNS_ZONE_SETFLAG(zone, |
| 4923 | DNS_ZONEFLG_LOADED| |
| 4924 | DNS_ZONEFLG_NEEDSTARTUPNOTIFY); |
| 4925 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SENDSECURE) && |
| 4926 | inline_raw(zone)) |
| 4927 | { |
| 4928 | if (zone->secure->db == NULL) { |
| 4929 | zone_send_securedb(zone, db); |
| 4930 | } else { |
| 4931 | zone_send_secureserial(zone, serial); |
| 4932 | } |
| 4933 | } |
| 4934 | } |
| 4935 | |
| 4936 | /* |
| 4937 | * Finished loading inline-signing zone; need to get status |
| 4938 | * from the raw side now. |
| 4939 | */ |
| 4940 | if (zone->type == dns_zone_master && inline_secure(zone)) { |
| 4941 | maybe_send_secure(zone); |
| 4942 | } |
| 4943 | |
| 4944 | result = ISC_R_SUCCESS; |
| 4945 | |
| 4946 | if (needdump) { |
| 4947 | if (zone->type == dns_zone_key) { |
| 4948 | zone_needdump(zone, 30); |
| 4949 | } else { |
| 4950 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 4951 | } |
| 4952 | } |
| 4953 | |
| 4954 | if (zone->task != NULL) { |
| 4955 | if (zone->type == dns_zone_master) { |
| 4956 | set_resigntime(zone); |
| 4957 | resume_signingwithkey(zone); |
| 4958 | resume_addnsec3chain(zone); |
| 4959 | } |
| 4960 | |
| 4961 | if (zone->type == dns_zone_master && |
| 4962 | !DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_NORESIGN) && |
| 4963 | dns_zone_isdynamic(zone, false) && |
| 4964 | dns_db_issecure(db)) |
| 4965 | { |
| 4966 | dns_name_t *name; |
| 4967 | dns_fixedname_t fixed; |
| 4968 | dns_rdataset_t next; |
| 4969 | |
| 4970 | dns_rdataset_init(&next); |
| 4971 | name = dns_fixedname_initname(&fixed); |
| 4972 | |
| 4973 | result = dns_db_getsigningtime(db, &next, name); |
| 4974 | if (result == ISC_R_SUCCESS) { |
| 4975 | isc_stdtime_t timenow; |
| 4976 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 4977 | char typebuf[DNS_RDATATYPE_FORMATSIZE]; |
| 4978 | |
| 4979 | isc_stdtime_get(&timenow); |
| 4980 | dns_name_format(name, namebuf, sizeof(namebuf)); |
| 4981 | dns_rdatatype_format(next.covers, |
| 4982 | typebuf, sizeof(typebuf)); |
| 4983 | dnssec_log(zone, ISC_LOG_DEBUG(3), |
| 4984 | "next resign: %s/%s " |
| 4985 | "in %d seconds" , namebuf, typebuf, |
| 4986 | next.resign - timenow - |
| 4987 | zone->sigresigninginterval); |
| 4988 | dns_rdataset_disassociate(&next); |
| 4989 | } else { |
| 4990 | dnssec_log(zone, ISC_LOG_WARNING, |
| 4991 | "signed dynamic zone has no " |
| 4992 | "resign event scheduled" ); |
| 4993 | } |
| 4994 | } |
| 4995 | |
| 4996 | zone_settimer(zone, &now); |
| 4997 | } |
| 4998 | |
| 4999 | /* |
| 5000 | * Clear old include list. |
| 5001 | */ |
| 5002 | for (inc = ISC_LIST_HEAD(zone->includes); |
| 5003 | inc != NULL; |
| 5004 | inc = ISC_LIST_HEAD(zone->includes)) |
| 5005 | { |
| 5006 | ISC_LIST_UNLINK(zone->includes, inc, link); |
| 5007 | isc_mem_free(zone->mctx, inc->name); |
| 5008 | isc_mem_put(zone->mctx, inc, sizeof(*inc)); |
| 5009 | } |
| 5010 | zone->nincludes = 0; |
| 5011 | |
| 5012 | /* |
| 5013 | * Transfer new include list. |
| 5014 | */ |
| 5015 | for (inc = ISC_LIST_HEAD(zone->newincludes); |
| 5016 | inc != NULL; |
| 5017 | inc = ISC_LIST_HEAD(zone->newincludes)) |
| 5018 | { |
| 5019 | ISC_LIST_UNLINK(zone->newincludes, inc, link); |
| 5020 | ISC_LIST_APPEND(zone->includes, inc, link); |
| 5021 | zone->nincludes++; |
| 5022 | } |
| 5023 | |
| 5024 | if (! dns_db_ispersistent(db)) { |
| 5025 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 5026 | ISC_LOG_INFO, "loaded serial %u%s" , serial, |
| 5027 | dns_db_issecure(db) ? " (DNSSEC signed)" : "" ); |
| 5028 | } |
| 5029 | |
| 5030 | if (!had_db && zone->type == dns_zone_mirror) { |
| 5031 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_INFO, |
| 5032 | "mirror zone is now in use" ); |
| 5033 | } |
| 5034 | |
| 5035 | zone->loadtime = loadtime; |
| 5036 | goto done; |
| 5037 | |
| 5038 | cleanup: |
| 5039 | if (zone->type == dns_zone_key && result != ISC_R_SUCCESS) { |
| 5040 | dnssec_log(zone, ISC_LOG_ERROR, |
| 5041 | "failed to initialize managed-keys (%s): " |
| 5042 | "DNSSEC validation is at risk" , |
| 5043 | isc_result_totext(result)); |
| 5044 | } |
| 5045 | |
| 5046 | for (inc = ISC_LIST_HEAD(zone->newincludes); |
| 5047 | inc != NULL; |
| 5048 | inc = ISC_LIST_HEAD(zone->newincludes)) |
| 5049 | { |
| 5050 | ISC_LIST_UNLINK(zone->newincludes, inc, link); |
| 5051 | isc_mem_free(zone->mctx, inc->name); |
| 5052 | isc_mem_put(zone->mctx, inc, sizeof(*inc)); |
| 5053 | } |
| 5054 | if (zone->type == dns_zone_slave || |
| 5055 | zone->type == dns_zone_mirror || |
| 5056 | zone->type == dns_zone_stub || |
| 5057 | zone->type == dns_zone_key || |
| 5058 | (zone->type == dns_zone_redirect && zone->masters != NULL)) |
| 5059 | { |
| 5060 | if (result != ISC_R_NOMEMORY) { |
| 5061 | if (zone->journal != NULL) { |
| 5062 | zone_saveunique(zone, zone->journal, |
| 5063 | "jn-XXXXXXXX" ); |
| 5064 | } |
| 5065 | if (zone->masterfile != NULL) { |
| 5066 | zone_saveunique(zone, zone->masterfile, |
| 5067 | "db-XXXXXXXX" ); |
| 5068 | } |
| 5069 | } |
| 5070 | |
| 5071 | /* Mark the zone for immediate refresh. */ |
| 5072 | zone->refreshtime = now; |
| 5073 | if (zone->task != NULL) { |
| 5074 | zone_settimer(zone, &now); |
| 5075 | } |
| 5076 | result = ISC_R_SUCCESS; |
| 5077 | } else if (zone->type == dns_zone_master || |
| 5078 | zone->type == dns_zone_redirect) |
| 5079 | { |
| 5080 | if (! (inline_secure(zone) && result == ISC_R_FILENOTFOUND)) { |
| 5081 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
| 5082 | ISC_LOG_ERROR, |
| 5083 | "not loaded due to errors." ); |
| 5084 | } else if (zone->type == dns_zone_master) { |
| 5085 | result = ISC_R_SUCCESS; |
| 5086 | } |
| 5087 | } |
| 5088 | |
| 5089 | done: |
| 5090 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING); |
| 5091 | /* |
| 5092 | * If this is an inline-signed zone and we were called for the raw |
| 5093 | * zone, we need to clear DNS_ZONEFLG_LOADPENDING for the secure zone |
| 5094 | * as well, but only if this is a reload, not an initial zone load: in |
| 5095 | * the former case, zone_postload() will not be run for the secure |
| 5096 | * zone; in the latter case, it will be. Check which case we are |
| 5097 | * dealing with by consulting the DNS_ZONEFLG_LOADED flag for the |
| 5098 | * secure zone: if it is set, this must be a reload. |
| 5099 | */ |
| 5100 | if (inline_raw(zone) && |
| 5101 | DNS_ZONE_FLAG(zone->secure, DNS_ZONEFLG_LOADED)) |
| 5102 | { |
| 5103 | DNS_ZONE_CLRFLAG(zone->secure, DNS_ZONEFLG_LOADPENDING); |
| 5104 | } |
| 5105 | |
| 5106 | zone_debuglog(zone, "zone_postload" , 99, "done" ); |
| 5107 | |
| 5108 | return (result); |
| 5109 | } |
| 5110 | |
| 5111 | static bool |
| 5112 | exit_check(dns_zone_t *zone) { |
| 5113 | REQUIRE(LOCKED_ZONE(zone)); |
| 5114 | |
| 5115 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) && zone->irefs == 0) { |
| 5116 | /* |
| 5117 | * DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0. |
| 5118 | */ |
| 5119 | INSIST(isc_refcount_current(&zone->erefs) == 0); |
| 5120 | return (true); |
| 5121 | } |
| 5122 | return (false); |
| 5123 | } |
| 5124 | |
| 5125 | static bool |
| 5126 | zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, |
| 5127 | dns_name_t *name, bool logit) |
| 5128 | { |
| 5129 | isc_result_t result; |
| 5130 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 5131 | char altbuf[DNS_NAME_FORMATSIZE]; |
| 5132 | dns_fixedname_t fixed; |
| 5133 | dns_name_t *foundname; |
| 5134 | int level; |
| 5135 | |
| 5136 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOCHECKNS)) |
| 5137 | return (true); |
| 5138 | |
| 5139 | if (zone->type == dns_zone_master) |
| 5140 | level = ISC_LOG_ERROR; |
| 5141 | else |
| 5142 | level = ISC_LOG_WARNING; |
| 5143 | |
| 5144 | foundname = dns_fixedname_initname(&fixed); |
| 5145 | |
| 5146 | result = dns_db_find(db, name, version, dns_rdatatype_a, |
| 5147 | 0, 0, NULL, foundname, NULL, NULL); |
| 5148 | if (result == ISC_R_SUCCESS) |
| 5149 | return (true); |
| 5150 | |
| 5151 | if (result == DNS_R_NXRRSET) { |
| 5152 | result = dns_db_find(db, name, version, dns_rdatatype_aaaa, |
| 5153 | 0, 0, NULL, foundname, NULL, NULL); |
| 5154 | if (result == ISC_R_SUCCESS) |
| 5155 | return (true); |
| 5156 | } |
| 5157 | |
| 5158 | if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || |
| 5159 | result == DNS_R_EMPTYNAME) { |
| 5160 | if (logit) { |
| 5161 | dns_name_format(name, namebuf, sizeof namebuf); |
| 5162 | dns_zone_log(zone, level, "NS '%s' has no address " |
| 5163 | "records (A or AAAA)" , namebuf); |
| 5164 | } |
| 5165 | return (false); |
| 5166 | } |
| 5167 | |
| 5168 | if (result == DNS_R_CNAME) { |
| 5169 | if (logit) { |
| 5170 | dns_name_format(name, namebuf, sizeof namebuf); |
| 5171 | dns_zone_log(zone, level, "NS '%s' is a CNAME " |
| 5172 | "(illegal)" , namebuf); |
| 5173 | } |
| 5174 | return (false); |
| 5175 | } |
| 5176 | |
| 5177 | if (result == DNS_R_DNAME) { |
| 5178 | if (logit) { |
| 5179 | dns_name_format(name, namebuf, sizeof namebuf); |
| 5180 | dns_name_format(foundname, altbuf, sizeof altbuf); |
| 5181 | dns_zone_log(zone, level, "NS '%s' is below a DNAME " |
| 5182 | "'%s' (illegal)" , namebuf, altbuf); |
| 5183 | } |
| 5184 | return (false); |
| 5185 | } |
| 5186 | |
| 5187 | return (true); |
| 5188 | } |
| 5189 | |
| 5190 | static isc_result_t |
| 5191 | zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node, |
| 5192 | dns_dbversion_t *version, unsigned int *nscount, |
| 5193 | unsigned int *errors, bool logit) |
| 5194 | { |
| 5195 | isc_result_t result; |
| 5196 | unsigned int count = 0; |
| 5197 | unsigned int ecount = 0; |
| 5198 | dns_rdataset_t rdataset; |
| 5199 | dns_rdata_t rdata; |
| 5200 | dns_rdata_ns_t ns; |
| 5201 | |
| 5202 | dns_rdataset_init(&rdataset); |
| 5203 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns, |
| 5204 | dns_rdatatype_none, 0, &rdataset, NULL); |
| 5205 | if (result == ISC_R_NOTFOUND) { |
| 5206 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 5207 | goto success; |
| 5208 | } |
| 5209 | if (result != ISC_R_SUCCESS) { |
| 5210 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 5211 | goto invalidate_rdataset; |
| 5212 | } |
| 5213 | |
| 5214 | result = dns_rdataset_first(&rdataset); |
| 5215 | while (result == ISC_R_SUCCESS) { |
| 5216 | if (errors != NULL && zone->rdclass == dns_rdataclass_in && |
| 5217 | (zone->type == dns_zone_master || |
| 5218 | zone->type == dns_zone_slave || |
| 5219 | zone->type == dns_zone_mirror)) |
| 5220 | { |
| 5221 | dns_rdata_init(&rdata); |
| 5222 | dns_rdataset_current(&rdataset, &rdata); |
| 5223 | result = dns_rdata_tostruct(&rdata, &ns, NULL); |
| 5224 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 5225 | if (dns_name_issubdomain(&ns.name, &zone->origin) && |
| 5226 | !zone_check_ns(zone, db, version, &ns.name, logit)) |
| 5227 | ecount++; |
| 5228 | } |
| 5229 | count++; |
| 5230 | result = dns_rdataset_next(&rdataset); |
| 5231 | } |
| 5232 | dns_rdataset_disassociate(&rdataset); |
| 5233 | |
| 5234 | success: |
| 5235 | if (nscount != NULL) |
| 5236 | *nscount = count; |
| 5237 | if (errors != NULL) |
| 5238 | *errors = ecount; |
| 5239 | |
| 5240 | result = ISC_R_SUCCESS; |
| 5241 | |
| 5242 | invalidate_rdataset: |
| 5243 | dns_rdataset_invalidate(&rdataset); |
| 5244 | |
| 5245 | return (result); |
| 5246 | } |
| 5247 | |
| 5248 | static isc_result_t |
| 5249 | zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, |
| 5250 | unsigned int *soacount, |
| 5251 | uint32_t *serial, uint32_t *refresh, |
| 5252 | uint32_t *retry, uint32_t *expire, |
| 5253 | uint32_t *minimum) |
| 5254 | { |
| 5255 | isc_result_t result; |
| 5256 | unsigned int count; |
| 5257 | dns_rdataset_t rdataset; |
| 5258 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 5259 | dns_rdata_soa_t soa; |
| 5260 | |
| 5261 | dns_rdataset_init(&rdataset); |
| 5262 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, |
| 5263 | dns_rdatatype_none, 0, &rdataset, NULL); |
| 5264 | if (result == ISC_R_NOTFOUND) { |
| 5265 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 5266 | if (soacount != NULL) |
| 5267 | *soacount = 0; |
| 5268 | if (serial != NULL) |
| 5269 | *serial = 0; |
| 5270 | if (refresh != NULL) |
| 5271 | *refresh = 0; |
| 5272 | if (retry != NULL) |
| 5273 | *retry = 0; |
| 5274 | if (expire != NULL) |
| 5275 | *expire = 0; |
| 5276 | if (minimum != NULL) |
| 5277 | *minimum = 0; |
| 5278 | result = ISC_R_SUCCESS; |
| 5279 | goto invalidate_rdataset; |
| 5280 | } |
| 5281 | if (result != ISC_R_SUCCESS) { |
| 5282 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 5283 | goto invalidate_rdataset; |
| 5284 | } |
| 5285 | |
| 5286 | count = 0; |
| 5287 | result = dns_rdataset_first(&rdataset); |
| 5288 | while (result == ISC_R_SUCCESS) { |
| 5289 | dns_rdata_init(&rdata); |
| 5290 | dns_rdataset_current(&rdataset, &rdata); |
| 5291 | count++; |
| 5292 | if (count == 1) { |
| 5293 | result = dns_rdata_tostruct(&rdata, &soa, NULL); |
| 5294 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 5295 | } |
| 5296 | |
| 5297 | result = dns_rdataset_next(&rdataset); |
| 5298 | dns_rdata_reset(&rdata); |
| 5299 | } |
| 5300 | dns_rdataset_disassociate(&rdataset); |
| 5301 | |
| 5302 | if (soacount != NULL) |
| 5303 | *soacount = count; |
| 5304 | |
| 5305 | if (count > 0) { |
| 5306 | if (serial != NULL) |
| 5307 | *serial = soa.serial; |
| 5308 | if (refresh != NULL) |
| 5309 | *refresh = soa.refresh; |
| 5310 | if (retry != NULL) |
| 5311 | *retry = soa.retry; |
| 5312 | if (expire != NULL) |
| 5313 | *expire = soa.expire; |
| 5314 | if (minimum != NULL) |
| 5315 | *minimum = soa.minimum; |
| 5316 | } else { |
| 5317 | if (soacount != NULL) |
| 5318 | *soacount = 0; |
| 5319 | if (serial != NULL) |
| 5320 | *serial = 0; |
| 5321 | if (refresh != NULL) |
| 5322 | *refresh = 0; |
| 5323 | if (retry != NULL) |
| 5324 | *retry = 0; |
| 5325 | if (expire != NULL) |
| 5326 | *expire = 0; |
| 5327 | if (minimum != NULL) |
| 5328 | *minimum = 0; |
| 5329 | } |
| 5330 | |
| 5331 | result = ISC_R_SUCCESS; |
| 5332 | |
| 5333 | invalidate_rdataset: |
| 5334 | dns_rdataset_invalidate(&rdataset); |
| 5335 | |
| 5336 | return (result); |
| 5337 | } |
| 5338 | |
| 5339 | /* |
| 5340 | * zone must be locked. |
| 5341 | */ |
| 5342 | static isc_result_t |
| 5343 | zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, |
| 5344 | unsigned int *soacount, uint32_t *serial, |
| 5345 | uint32_t *refresh, uint32_t *retry, |
| 5346 | uint32_t *expire, uint32_t *minimum, |
| 5347 | unsigned int *errors) |
| 5348 | { |
| 5349 | isc_result_t result; |
| 5350 | isc_result_t answer = ISC_R_SUCCESS; |
| 5351 | dns_dbversion_t *version = NULL; |
| 5352 | dns_dbnode_t *node; |
| 5353 | |
| 5354 | REQUIRE(db != NULL); |
| 5355 | REQUIRE(zone != NULL); |
| 5356 | |
| 5357 | dns_db_currentversion(db, &version); |
| 5358 | |
| 5359 | if (nscount != NULL) |
| 5360 | *nscount = 0; |
| 5361 | if (soacount != NULL) |
| 5362 | *soacount = 0; |
| 5363 | if (serial != NULL) |
| 5364 | *serial = 0; |
| 5365 | if (refresh != NULL) |
| 5366 | *refresh = 0; |
| 5367 | if (retry != NULL) |
| 5368 | *retry = 0; |
| 5369 | if (expire != NULL) |
| 5370 | *expire = 0; |
| 5371 | if (errors != NULL) |
| 5372 | *errors = 0; |
| 5373 | |
| 5374 | node = NULL; |
| 5375 | result = dns_db_findnode(db, &zone->origin, false, &node); |
| 5376 | if (result != ISC_R_SUCCESS) { |
| 5377 | answer = result; |
| 5378 | goto closeversion; |
| 5379 | } |
| 5380 | |
| 5381 | if (nscount != NULL || errors != NULL) { |
| 5382 | result = zone_count_ns_rr(zone, db, node, version, |
| 5383 | nscount, errors, true); |
| 5384 | if (result != ISC_R_SUCCESS) |
| 5385 | answer = result; |
| 5386 | } |
| 5387 | |
| 5388 | if (soacount != NULL || serial != NULL || refresh != NULL |
| 5389 | || retry != NULL || expire != NULL || minimum != NULL) { |
| 5390 | result = zone_load_soa_rr(db, node, version, soacount, |
| 5391 | serial, refresh, retry, expire, |
| 5392 | minimum); |
| 5393 | if (result != ISC_R_SUCCESS) |
| 5394 | answer = result; |
| 5395 | } |
| 5396 | |
| 5397 | dns_db_detachnode(db, &node); |
| 5398 | closeversion: |
| 5399 | dns_db_closeversion(db, &version, false); |
| 5400 | |
| 5401 | return (answer); |
| 5402 | } |
| 5403 | |
| 5404 | void |
| 5405 | dns_zone_attach(dns_zone_t *source, dns_zone_t **target) { |
| 5406 | REQUIRE(DNS_ZONE_VALID(source)); |
| 5407 | REQUIRE(target != NULL && *target == NULL); |
| 5408 | isc_refcount_increment(&source->erefs); |
| 5409 | *target = source; |
| 5410 | } |
| 5411 | |
| 5412 | void |
| 5413 | dns_zone_detach(dns_zone_t **zonep) { |
| 5414 | REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); |
| 5415 | dns_zone_t *zone = *zonep; |
| 5416 | *zonep = NULL; |
| 5417 | |
| 5418 | bool free_now = false; |
| 5419 | dns_zone_t *raw = NULL; |
| 5420 | dns_zone_t *secure = NULL; |
| 5421 | if (isc_refcount_decrement(&zone->erefs) == 1) { |
| 5422 | isc_refcount_destroy(&zone->erefs); |
| 5423 | |
| 5424 | LOCK_ZONE(zone); |
| 5425 | INSIST(zone != zone->raw); |
| 5426 | /* |
| 5427 | * We just detached the last external reference. |
| 5428 | */ |
| 5429 | if (zone->task != NULL) { |
| 5430 | /* |
| 5431 | * This zone is being managed. Post |
| 5432 | * its control event and let it clean |
| 5433 | * up synchronously in the context of |
| 5434 | * its task. |
| 5435 | */ |
| 5436 | isc_event_t *ev = &zone->ctlevent; |
| 5437 | isc_task_send(zone->task, &ev); |
| 5438 | } else { |
| 5439 | /* |
| 5440 | * This zone is not being managed; it has |
| 5441 | * no task and can have no outstanding |
| 5442 | * events. Free it immediately. |
| 5443 | */ |
| 5444 | /* |
| 5445 | * Unmanaged zones should not have non-null views; |
| 5446 | * we have no way of detaching from the view here |
| 5447 | * without causing deadlock because this code is called |
| 5448 | * with the view already locked. |
| 5449 | */ |
| 5450 | INSIST(zone->view == NULL); |
| 5451 | free_now = true; |
| 5452 | raw = zone->raw; |
| 5453 | zone->raw = NULL; |
| 5454 | secure = zone->secure; |
| 5455 | zone->secure = NULL; |
| 5456 | } |
| 5457 | UNLOCK_ZONE(zone); |
| 5458 | } |
| 5459 | if (free_now) { |
| 5460 | if (raw != NULL) { |
| 5461 | dns_zone_detach(&raw); |
| 5462 | } |
| 5463 | if (secure != NULL) { |
| 5464 | dns_zone_idetach(&secure); |
| 5465 | } |
| 5466 | zone_free(zone); |
| 5467 | } |
| 5468 | } |
| 5469 | |
| 5470 | void |
| 5471 | dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) { |
| 5472 | REQUIRE(DNS_ZONE_VALID(source)); |
| 5473 | REQUIRE(target != NULL && *target == NULL); |
| 5474 | LOCK_ZONE(source); |
| 5475 | zone_iattach(source, target); |
| 5476 | UNLOCK_ZONE(source); |
| 5477 | } |
| 5478 | |
| 5479 | static void |
| 5480 | zone_iattach(dns_zone_t *source, dns_zone_t **target) { |
| 5481 | |
| 5482 | /* |
| 5483 | * 'source' locked by caller. |
| 5484 | */ |
| 5485 | REQUIRE(LOCKED_ZONE(source)); |
| 5486 | REQUIRE(DNS_ZONE_VALID(source)); |
| 5487 | REQUIRE(target != NULL && *target == NULL); |
| 5488 | INSIST(source->irefs + isc_refcount_current(&source->erefs) > 0); |
| 5489 | source->irefs++; |
| 5490 | INSIST(source->irefs != 0); |
| 5491 | *target = source; |
| 5492 | } |
| 5493 | |
| 5494 | static void |
| 5495 | zone_idetach(dns_zone_t **zonep) { |
| 5496 | dns_zone_t *zone; |
| 5497 | |
| 5498 | /* |
| 5499 | * 'zone' locked by caller. |
| 5500 | */ |
| 5501 | REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); |
| 5502 | zone = *zonep; |
| 5503 | REQUIRE(LOCKED_ZONE(*zonep)); |
| 5504 | *zonep = NULL; |
| 5505 | |
| 5506 | INSIST(zone->irefs > 0); |
| 5507 | zone->irefs--; |
| 5508 | INSIST(zone->irefs + isc_refcount_current(&zone->erefs) > 0); |
| 5509 | } |
| 5510 | |
| 5511 | void |
| 5512 | dns_zone_idetach(dns_zone_t **zonep) { |
| 5513 | dns_zone_t *zone; |
| 5514 | bool free_needed; |
| 5515 | |
| 5516 | REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); |
| 5517 | zone = *zonep; |
| 5518 | *zonep = NULL; |
| 5519 | |
| 5520 | LOCK_ZONE(zone); |
| 5521 | INSIST(zone->irefs > 0); |
| 5522 | zone->irefs--; |
| 5523 | free_needed = exit_check(zone); |
| 5524 | UNLOCK_ZONE(zone); |
| 5525 | if (free_needed) |
| 5526 | zone_free(zone); |
| 5527 | } |
| 5528 | |
| 5529 | isc_mem_t * |
| 5530 | dns_zone_getmctx(dns_zone_t *zone) { |
| 5531 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5532 | |
| 5533 | return (zone->mctx); |
| 5534 | } |
| 5535 | |
| 5536 | dns_zonemgr_t * |
| 5537 | dns_zone_getmgr(dns_zone_t *zone) { |
| 5538 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5539 | |
| 5540 | return (zone->zmgr); |
| 5541 | } |
| 5542 | |
| 5543 | void |
| 5544 | dns_zone_setflag(dns_zone_t *zone, unsigned int flags, bool value) { |
| 5545 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5546 | |
| 5547 | LOCK_ZONE(zone); |
| 5548 | if (value) |
| 5549 | DNS_ZONE_SETFLAG(zone, flags); |
| 5550 | else |
| 5551 | DNS_ZONE_CLRFLAG(zone, flags); |
| 5552 | UNLOCK_ZONE(zone); |
| 5553 | } |
| 5554 | |
| 5555 | void |
| 5556 | dns_zone_setoption(dns_zone_t *zone, dns_zoneopt_t option, |
| 5557 | bool value) |
| 5558 | { |
| 5559 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5560 | |
| 5561 | LOCK_ZONE(zone); |
| 5562 | if (value) |
| 5563 | zone->options |= option; |
| 5564 | else |
| 5565 | zone->options &= ~option; |
| 5566 | UNLOCK_ZONE(zone); |
| 5567 | } |
| 5568 | |
| 5569 | dns_zoneopt_t |
| 5570 | dns_zone_getoptions(dns_zone_t *zone) { |
| 5571 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5572 | |
| 5573 | return (zone->options); |
| 5574 | } |
| 5575 | |
| 5576 | void |
| 5577 | dns_zone_setkeyopt(dns_zone_t *zone, unsigned int keyopt, bool value) |
| 5578 | { |
| 5579 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5580 | |
| 5581 | LOCK_ZONE(zone); |
| 5582 | if (value) |
| 5583 | zone->keyopts |= keyopt; |
| 5584 | else |
| 5585 | zone->keyopts &= ~keyopt; |
| 5586 | UNLOCK_ZONE(zone); |
| 5587 | } |
| 5588 | |
| 5589 | unsigned int |
| 5590 | dns_zone_getkeyopts(dns_zone_t *zone) { |
| 5591 | |
| 5592 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5593 | |
| 5594 | return (zone->keyopts); |
| 5595 | } |
| 5596 | |
| 5597 | isc_result_t |
| 5598 | dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) { |
| 5599 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5600 | |
| 5601 | LOCK_ZONE(zone); |
| 5602 | zone->xfrsource4 = *xfrsource; |
| 5603 | UNLOCK_ZONE(zone); |
| 5604 | |
| 5605 | return (ISC_R_SUCCESS); |
| 5606 | } |
| 5607 | |
| 5608 | isc_sockaddr_t * |
| 5609 | dns_zone_getxfrsource4(dns_zone_t *zone) { |
| 5610 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5611 | return (&zone->xfrsource4); |
| 5612 | } |
| 5613 | |
| 5614 | isc_result_t |
| 5615 | dns_zone_setxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp) { |
| 5616 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5617 | |
| 5618 | LOCK_ZONE(zone); |
| 5619 | zone->xfrsource4dscp = dscp; |
| 5620 | UNLOCK_ZONE(zone); |
| 5621 | |
| 5622 | return (ISC_R_SUCCESS); |
| 5623 | } |
| 5624 | |
| 5625 | isc_dscp_t |
| 5626 | dns_zone_getxfrsource4dscp(dns_zone_t *zone) { |
| 5627 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5628 | return (zone->xfrsource4dscp); |
| 5629 | } |
| 5630 | |
| 5631 | isc_result_t |
| 5632 | dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) { |
| 5633 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5634 | |
| 5635 | LOCK_ZONE(zone); |
| 5636 | zone->xfrsource6 = *xfrsource; |
| 5637 | UNLOCK_ZONE(zone); |
| 5638 | |
| 5639 | return (ISC_R_SUCCESS); |
| 5640 | } |
| 5641 | |
| 5642 | isc_sockaddr_t * |
| 5643 | dns_zone_getxfrsource6(dns_zone_t *zone) { |
| 5644 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5645 | return (&zone->xfrsource6); |
| 5646 | } |
| 5647 | |
| 5648 | isc_dscp_t |
| 5649 | dns_zone_getxfrsource6dscp(dns_zone_t *zone) { |
| 5650 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5651 | return (zone->xfrsource6dscp); |
| 5652 | } |
| 5653 | |
| 5654 | isc_result_t |
| 5655 | dns_zone_setxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp) { |
| 5656 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5657 | |
| 5658 | LOCK_ZONE(zone); |
| 5659 | zone->xfrsource6dscp = dscp; |
| 5660 | UNLOCK_ZONE(zone); |
| 5661 | |
| 5662 | return (ISC_R_SUCCESS); |
| 5663 | } |
| 5664 | |
| 5665 | isc_result_t |
| 5666 | dns_zone_setaltxfrsource4(dns_zone_t *zone, |
| 5667 | const isc_sockaddr_t *altxfrsource) |
| 5668 | { |
| 5669 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5670 | |
| 5671 | LOCK_ZONE(zone); |
| 5672 | zone->altxfrsource4 = *altxfrsource; |
| 5673 | UNLOCK_ZONE(zone); |
| 5674 | |
| 5675 | return (ISC_R_SUCCESS); |
| 5676 | } |
| 5677 | |
| 5678 | isc_sockaddr_t * |
| 5679 | dns_zone_getaltxfrsource4(dns_zone_t *zone) { |
| 5680 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5681 | return (&zone->altxfrsource4); |
| 5682 | } |
| 5683 | |
| 5684 | isc_result_t |
| 5685 | dns_zone_setaltxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp) { |
| 5686 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5687 | |
| 5688 | LOCK_ZONE(zone); |
| 5689 | zone->altxfrsource4dscp = dscp; |
| 5690 | UNLOCK_ZONE(zone); |
| 5691 | |
| 5692 | return (ISC_R_SUCCESS); |
| 5693 | } |
| 5694 | |
| 5695 | isc_dscp_t |
| 5696 | dns_zone_getaltxfrsource4dscp(dns_zone_t *zone) { |
| 5697 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5698 | return (zone->altxfrsource4dscp); |
| 5699 | } |
| 5700 | |
| 5701 | isc_result_t |
| 5702 | dns_zone_setaltxfrsource6(dns_zone_t *zone, |
| 5703 | const isc_sockaddr_t *altxfrsource) |
| 5704 | { |
| 5705 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5706 | |
| 5707 | LOCK_ZONE(zone); |
| 5708 | zone->altxfrsource6 = *altxfrsource; |
| 5709 | UNLOCK_ZONE(zone); |
| 5710 | |
| 5711 | return (ISC_R_SUCCESS); |
| 5712 | } |
| 5713 | |
| 5714 | isc_sockaddr_t * |
| 5715 | dns_zone_getaltxfrsource6(dns_zone_t *zone) { |
| 5716 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5717 | return (&zone->altxfrsource6); |
| 5718 | } |
| 5719 | |
| 5720 | isc_result_t |
| 5721 | dns_zone_setaltxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp) { |
| 5722 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5723 | |
| 5724 | LOCK_ZONE(zone); |
| 5725 | zone->altxfrsource6dscp = dscp; |
| 5726 | UNLOCK_ZONE(zone); |
| 5727 | |
| 5728 | return (ISC_R_SUCCESS); |
| 5729 | } |
| 5730 | |
| 5731 | isc_dscp_t |
| 5732 | dns_zone_getaltxfrsource6dscp(dns_zone_t *zone) { |
| 5733 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5734 | return (zone->altxfrsource6dscp); |
| 5735 | } |
| 5736 | |
| 5737 | isc_result_t |
| 5738 | dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { |
| 5739 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5740 | |
| 5741 | LOCK_ZONE(zone); |
| 5742 | zone->notifysrc4 = *notifysrc; |
| 5743 | UNLOCK_ZONE(zone); |
| 5744 | |
| 5745 | return (ISC_R_SUCCESS); |
| 5746 | } |
| 5747 | |
| 5748 | isc_sockaddr_t * |
| 5749 | dns_zone_getnotifysrc4(dns_zone_t *zone) { |
| 5750 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5751 | return (&zone->notifysrc4); |
| 5752 | } |
| 5753 | |
| 5754 | isc_result_t |
| 5755 | dns_zone_setnotifysrc4dscp(dns_zone_t *zone, isc_dscp_t dscp) { |
| 5756 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5757 | |
| 5758 | LOCK_ZONE(zone); |
| 5759 | zone->notifysrc4dscp = dscp; |
| 5760 | UNLOCK_ZONE(zone); |
| 5761 | |
| 5762 | return (ISC_R_SUCCESS); |
| 5763 | } |
| 5764 | |
| 5765 | isc_dscp_t |
| 5766 | dns_zone_getnotifysrc4dscp(dns_zone_t *zone) { |
| 5767 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5768 | return (zone->notifysrc4dscp); |
| 5769 | } |
| 5770 | |
| 5771 | isc_result_t |
| 5772 | dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { |
| 5773 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5774 | |
| 5775 | LOCK_ZONE(zone); |
| 5776 | zone->notifysrc6 = *notifysrc; |
| 5777 | UNLOCK_ZONE(zone); |
| 5778 | |
| 5779 | return (ISC_R_SUCCESS); |
| 5780 | } |
| 5781 | |
| 5782 | isc_sockaddr_t * |
| 5783 | dns_zone_getnotifysrc6(dns_zone_t *zone) { |
| 5784 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5785 | return (&zone->notifysrc6); |
| 5786 | } |
| 5787 | |
| 5788 | static bool |
| 5789 | same_addrs(isc_sockaddr_t const *oldlist, isc_sockaddr_t const *newlist, |
| 5790 | uint32_t count) |
| 5791 | { |
| 5792 | unsigned int i; |
| 5793 | |
| 5794 | for (i = 0; i < count; i++) |
| 5795 | if (!isc_sockaddr_equal(&oldlist[i], &newlist[i])) |
| 5796 | return (false); |
| 5797 | return (true); |
| 5798 | } |
| 5799 | |
| 5800 | static bool |
| 5801 | same_keynames(dns_name_t * const *oldlist, dns_name_t * const *newlist, |
| 5802 | uint32_t count) |
| 5803 | { |
| 5804 | unsigned int i; |
| 5805 | |
| 5806 | if (oldlist == NULL && newlist == NULL) |
| 5807 | return (true); |
| 5808 | if (oldlist == NULL || newlist == NULL) |
| 5809 | return (false); |
| 5810 | |
| 5811 | for (i = 0; i < count; i++) { |
| 5812 | if (oldlist[i] == NULL && newlist[i] == NULL) |
| 5813 | continue; |
| 5814 | if (oldlist[i] == NULL || newlist[i] == NULL || |
| 5815 | !dns_name_equal(oldlist[i], newlist[i])) |
| 5816 | return (false); |
| 5817 | } |
| 5818 | return (true); |
| 5819 | } |
| 5820 | |
| 5821 | static void |
| 5822 | clear_addresskeylist(isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, |
| 5823 | dns_name_t ***keynamesp, unsigned int *countp, |
| 5824 | isc_mem_t *mctx) |
| 5825 | { |
| 5826 | unsigned int count; |
| 5827 | isc_sockaddr_t *addrs; |
| 5828 | isc_dscp_t *dscps; |
| 5829 | dns_name_t **keynames; |
| 5830 | |
| 5831 | REQUIRE(countp != NULL && addrsp != NULL && dscpsp != NULL && |
| 5832 | keynamesp != NULL); |
| 5833 | |
| 5834 | count = *countp; |
| 5835 | *countp = 0; |
| 5836 | addrs = *addrsp; |
| 5837 | *addrsp = NULL; |
| 5838 | dscps = *dscpsp; |
| 5839 | *dscpsp = NULL; |
| 5840 | keynames = *keynamesp; |
| 5841 | *keynamesp = NULL; |
| 5842 | |
| 5843 | if (addrs != NULL) |
| 5844 | isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t)); |
| 5845 | |
| 5846 | if (dscps != NULL) |
| 5847 | isc_mem_put(mctx, dscps, count * sizeof(isc_dscp_t)); |
| 5848 | |
| 5849 | if (keynames != NULL) { |
| 5850 | unsigned int i; |
| 5851 | for (i = 0; i < count; i++) { |
| 5852 | if (keynames[i] != NULL) { |
| 5853 | dns_name_free(keynames[i], mctx); |
| 5854 | isc_mem_put(mctx, keynames[i], |
| 5855 | sizeof(dns_name_t)); |
| 5856 | keynames[i] = NULL; |
| 5857 | } |
| 5858 | } |
| 5859 | isc_mem_put(mctx, keynames, count * sizeof(dns_name_t *)); |
| 5860 | } |
| 5861 | } |
| 5862 | |
| 5863 | static isc_result_t |
| 5864 | set_addrkeylist(unsigned int count, |
| 5865 | const isc_sockaddr_t *addrs, isc_sockaddr_t **newaddrsp, |
| 5866 | const isc_dscp_t *dscp, isc_dscp_t **newdscpp, |
| 5867 | dns_name_t **names, dns_name_t ***newnamesp, |
| 5868 | isc_mem_t *mctx) |
| 5869 | { |
| 5870 | isc_result_t result; |
| 5871 | isc_sockaddr_t *newaddrs = NULL; |
| 5872 | isc_dscp_t *newdscp = NULL; |
| 5873 | dns_name_t **newnames = NULL; |
| 5874 | unsigned int i; |
| 5875 | |
| 5876 | REQUIRE(newaddrsp != NULL && *newaddrsp == NULL); |
| 5877 | REQUIRE(newdscpp != NULL && *newdscpp == NULL); |
| 5878 | REQUIRE(newnamesp != NULL && *newnamesp == NULL); |
| 5879 | |
| 5880 | newaddrs = isc_mem_get(mctx, count * sizeof(*newaddrs)); |
| 5881 | if (newaddrs == NULL) |
| 5882 | return (ISC_R_NOMEMORY); |
| 5883 | memmove(newaddrs, addrs, count * sizeof(*newaddrs)); |
| 5884 | |
| 5885 | if (dscp != NULL) { |
| 5886 | newdscp = isc_mem_get(mctx, count * sizeof(*newdscp)); |
| 5887 | if (newdscp == NULL) { |
| 5888 | isc_mem_put(mctx, newaddrs, count * sizeof(*newaddrs)); |
| 5889 | return (ISC_R_NOMEMORY); |
| 5890 | } |
| 5891 | memmove(newdscp, dscp, count * sizeof(*newdscp)); |
| 5892 | } else |
| 5893 | newdscp = NULL; |
| 5894 | |
| 5895 | if (names != NULL) { |
| 5896 | newnames = isc_mem_get(mctx, count * sizeof(*newnames)); |
| 5897 | if (newnames == NULL) { |
| 5898 | if (newdscp != NULL) |
| 5899 | isc_mem_put(mctx, newdscp, |
| 5900 | count * sizeof(*newdscp)); |
| 5901 | isc_mem_put(mctx, newaddrs, count * sizeof(*newaddrs)); |
| 5902 | return (ISC_R_NOMEMORY); |
| 5903 | } |
| 5904 | for (i = 0; i < count; i++) |
| 5905 | newnames[i] = NULL; |
| 5906 | for (i = 0; i < count; i++) { |
| 5907 | if (names[i] != NULL) { |
| 5908 | newnames[i] = isc_mem_get(mctx, |
| 5909 | sizeof(dns_name_t)); |
| 5910 | if (newnames[i] == NULL) |
| 5911 | goto allocfail; |
| 5912 | dns_name_init(newnames[i], NULL); |
| 5913 | result = dns_name_dup(names[i], mctx, |
| 5914 | newnames[i]); |
| 5915 | if (result != ISC_R_SUCCESS) { |
| 5916 | allocfail: |
| 5917 | for (i = 0; i < count; i++) |
| 5918 | if (newnames[i] != NULL) |
| 5919 | dns_name_free( |
| 5920 | newnames[i], |
| 5921 | mctx); |
| 5922 | isc_mem_put(mctx, newaddrs, |
| 5923 | count * sizeof(*newaddrs)); |
| 5924 | isc_mem_put(mctx, newdscp, |
| 5925 | count * sizeof(*newdscp)); |
| 5926 | isc_mem_put(mctx, newnames, |
| 5927 | count * sizeof(*newnames)); |
| 5928 | return (ISC_R_NOMEMORY); |
| 5929 | } |
| 5930 | } |
| 5931 | } |
| 5932 | } else |
| 5933 | newnames = NULL; |
| 5934 | |
| 5935 | *newdscpp = newdscp; |
| 5936 | *newaddrsp = newaddrs; |
| 5937 | *newnamesp = newnames; |
| 5938 | return (ISC_R_SUCCESS); |
| 5939 | } |
| 5940 | |
| 5941 | isc_result_t |
| 5942 | dns_zone_setnotifysrc6dscp(dns_zone_t *zone, isc_dscp_t dscp) { |
| 5943 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5944 | |
| 5945 | LOCK_ZONE(zone); |
| 5946 | zone->notifysrc6dscp = dscp; |
| 5947 | UNLOCK_ZONE(zone); |
| 5948 | |
| 5949 | return (ISC_R_SUCCESS); |
| 5950 | } |
| 5951 | |
| 5952 | isc_dscp_t |
| 5953 | dns_zone_getnotifysrc6dscp(dns_zone_t *zone) { |
| 5954 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5955 | return (zone->notifysrc6dscp); |
| 5956 | } |
| 5957 | |
| 5958 | isc_result_t |
| 5959 | dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify, |
| 5960 | uint32_t count) |
| 5961 | { |
| 5962 | return (dns_zone_setalsonotifydscpkeys(zone, notify, NULL, NULL, |
| 5963 | count)); |
| 5964 | } |
| 5965 | |
| 5966 | isc_result_t |
| 5967 | dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, |
| 5968 | dns_name_t **keynames, uint32_t count) |
| 5969 | { |
| 5970 | return (dns_zone_setalsonotifydscpkeys(zone, notify, NULL, keynames, |
| 5971 | count)); |
| 5972 | } |
| 5973 | |
| 5974 | isc_result_t |
| 5975 | dns_zone_setalsonotifydscpkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, |
| 5976 | const isc_dscp_t *dscps, dns_name_t **keynames, |
| 5977 | uint32_t count) |
| 5978 | { |
| 5979 | isc_result_t result; |
| 5980 | isc_sockaddr_t *newaddrs = NULL; |
| 5981 | isc_dscp_t *newdscps = NULL; |
| 5982 | dns_name_t **newnames = NULL; |
| 5983 | |
| 5984 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 5985 | REQUIRE(count == 0 || notify != NULL); |
| 5986 | if (keynames != NULL) |
| 5987 | REQUIRE(count != 0); |
| 5988 | |
| 5989 | LOCK_ZONE(zone); |
| 5990 | |
| 5991 | if (count == zone->notifycnt && |
| 5992 | same_addrs(zone->notify, notify, count) && |
| 5993 | same_keynames(zone->notifykeynames, keynames, count)) |
| 5994 | goto unlock; |
| 5995 | |
| 5996 | clear_addresskeylist(&zone->notify, &zone->notifydscp, |
| 5997 | &zone->notifykeynames, &zone->notifycnt, |
| 5998 | zone->mctx); |
| 5999 | |
| 6000 | if (count == 0) |
| 6001 | goto unlock; |
| 6002 | |
| 6003 | /* |
| 6004 | * Set up the notify and notifykey lists |
| 6005 | */ |
| 6006 | result = set_addrkeylist(count, notify, &newaddrs, dscps, &newdscps, |
| 6007 | keynames, &newnames, zone->mctx); |
| 6008 | if (result != ISC_R_SUCCESS) |
| 6009 | goto unlock; |
| 6010 | |
| 6011 | /* |
| 6012 | * Everything is ok so attach to the zone. |
| 6013 | */ |
| 6014 | zone->notify = newaddrs; |
| 6015 | zone->notifydscp = newdscps; |
| 6016 | zone->notifykeynames = newnames; |
| 6017 | zone->notifycnt = count; |
| 6018 | unlock: |
| 6019 | UNLOCK_ZONE(zone); |
| 6020 | return (ISC_R_SUCCESS); |
| 6021 | } |
| 6022 | |
| 6023 | isc_result_t |
| 6024 | dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters, |
| 6025 | uint32_t count) |
| 6026 | { |
| 6027 | isc_result_t result; |
| 6028 | |
| 6029 | result = dns_zone_setmasterswithkeys(zone, masters, NULL, count); |
| 6030 | return (result); |
| 6031 | } |
| 6032 | |
| 6033 | isc_result_t |
| 6034 | dns_zone_setmasterswithkeys(dns_zone_t *zone, |
| 6035 | const isc_sockaddr_t *masters, |
| 6036 | dns_name_t **keynames, |
| 6037 | uint32_t count) |
| 6038 | { |
| 6039 | isc_result_t result = ISC_R_SUCCESS; |
| 6040 | isc_sockaddr_t *newaddrs = NULL; |
| 6041 | isc_dscp_t *newdscps = NULL; |
| 6042 | dns_name_t **newnames = NULL; |
| 6043 | bool *newok; |
| 6044 | unsigned int i; |
| 6045 | |
| 6046 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 6047 | REQUIRE(count == 0 || masters != NULL); |
| 6048 | if (keynames != NULL) { |
| 6049 | REQUIRE(count != 0); |
| 6050 | } |
| 6051 | |
| 6052 | LOCK_ZONE(zone); |
| 6053 | /* |
| 6054 | * The refresh code assumes that 'masters' wouldn't change under it. |
| 6055 | * If it will change then kill off any current refresh in progress |
| 6056 | * and update the masters info. If it won't change then we can just |
| 6057 | * unlock and exit. |
| 6058 | */ |
| 6059 | if (count != zone->masterscnt || |
| 6060 | !same_addrs(zone->masters, masters, count) || |
| 6061 | !same_keynames(zone->masterkeynames, keynames, count)) { |
| 6062 | if (zone->request != NULL) |
| 6063 | dns_request_cancel(zone->request); |
| 6064 | } else |
| 6065 | goto unlock; |
| 6066 | |
| 6067 | /* |
| 6068 | * This needs to happen before clear_addresskeylist() sets |
| 6069 | * zone->masterscnt to 0: |
| 6070 | */ |
| 6071 | if (zone->mastersok != NULL) { |
| 6072 | isc_mem_put(zone->mctx, zone->mastersok, |
| 6073 | zone->masterscnt * sizeof(bool)); |
| 6074 | zone->mastersok = NULL; |
| 6075 | } |
| 6076 | clear_addresskeylist(&zone->masters, &zone->masterdscps, |
| 6077 | &zone->masterkeynames, &zone->masterscnt, |
| 6078 | zone->mctx); |
| 6079 | /* |
| 6080 | * If count == 0, don't allocate any space for masters, mastersok or |
| 6081 | * keynames so internally, those pointers are NULL if count == 0 |
| 6082 | */ |
| 6083 | if (count == 0) |
| 6084 | goto unlock; |
| 6085 | |
| 6086 | /* |
| 6087 | * mastersok must contain count elements |
| 6088 | */ |
| 6089 | newok = isc_mem_get(zone->mctx, count * sizeof(*newok)); |
| 6090 | if (newok == NULL) { |
| 6091 | result = ISC_R_NOMEMORY; |
| 6092 | isc_mem_put(zone->mctx, newaddrs, count * sizeof(*newaddrs)); |
| 6093 | goto unlock; |
| 6094 | }; |
| 6095 | for (i = 0; i < count; i++) |
| 6096 | newok[i] = false; |
| 6097 | |
| 6098 | /* |
| 6099 | * Now set up the masters and masterkey lists |
| 6100 | */ |
| 6101 | result = set_addrkeylist(count, masters, &newaddrs, NULL, &newdscps, |
| 6102 | keynames, &newnames, zone->mctx); |
| 6103 | INSIST(newdscps == NULL); |
| 6104 | if (result != ISC_R_SUCCESS) { |
| 6105 | isc_mem_put(zone->mctx, newok, count * sizeof(*newok)); |
| 6106 | goto unlock; |
| 6107 | } |
| 6108 | |
| 6109 | /* |
| 6110 | * Everything is ok so attach to the zone. |
| 6111 | */ |
| 6112 | zone->curmaster = 0; |
| 6113 | zone->mastersok = newok; |
| 6114 | zone->masters = newaddrs; |
| 6115 | zone->masterdscps = newdscps; |
| 6116 | zone->masterkeynames = newnames; |
| 6117 | zone->masterscnt = count; |
| 6118 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS); |
| 6119 | |
| 6120 | unlock: |
| 6121 | UNLOCK_ZONE(zone); |
| 6122 | return (result); |
| 6123 | } |
| 6124 | |
| 6125 | isc_result_t |
| 6126 | dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) { |
| 6127 | isc_result_t result = ISC_R_SUCCESS; |
| 6128 | |
| 6129 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 6130 | |
| 6131 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 6132 | if (zone->db == NULL) |
| 6133 | result = DNS_R_NOTLOADED; |
| 6134 | else |
| 6135 | dns_db_attach(zone->db, dpb); |
| 6136 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 6137 | |
| 6138 | return (result); |
| 6139 | } |
| 6140 | |
| 6141 | void |
| 6142 | dns_zone_setdb(dns_zone_t *zone, dns_db_t *db) { |
| 6143 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 6144 | REQUIRE(zone->type == dns_zone_staticstub); |
| 6145 | |
| 6146 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); |
| 6147 | REQUIRE(zone->db == NULL); |
| 6148 | dns_db_attach(db, &zone->db); |
| 6149 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
| 6150 | } |
| 6151 | |
| 6152 | /* |
| 6153 | * Co-ordinates the starting of routine jobs. |
| 6154 | */ |
| 6155 | void |
| 6156 | dns_zone_maintenance(dns_zone_t *zone) { |
| 6157 | const char me[] = "dns_zone_maintenance" ; |
| 6158 | isc_time_t now; |
| 6159 | |
| 6160 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 6161 | ENTER; |
| 6162 | |
| 6163 | LOCK_ZONE(zone); |
| 6164 | TIME_NOW(&now); |
| 6165 | zone_settimer(zone, &now); |
| 6166 | UNLOCK_ZONE(zone); |
| 6167 | } |
| 6168 | |
| 6169 | static inline bool |
| 6170 | was_dumping(dns_zone_t *zone) { |
| 6171 | bool dumping; |
| 6172 | |
| 6173 | REQUIRE(LOCKED_ZONE(zone)); |
| 6174 | |
| 6175 | dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING); |
| 6176 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING); |
| 6177 | if (!dumping) { |
| 6178 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); |
| 6179 | isc_time_settoepoch(&zone->dumptime); |
| 6180 | } |
| 6181 | return (dumping); |
| 6182 | } |
| 6183 | |
| 6184 | /*% |
| 6185 | * Find up to 'maxkeys' DNSSEC keys used for signing version 'ver' of database |
| 6186 | * 'db' for zone 'zone' in its key directory, then load these keys into 'keys'. |
| 6187 | * Only load the public part of a given key if it is not active at timestamp |
| 6188 | * 'now'. Store the number of keys found in 'nkeys'. |
| 6189 | */ |
| 6190 | isc_result_t |
| 6191 | dns__zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
| 6192 | isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys, |
| 6193 | dst_key_t **keys, unsigned int *nkeys) |
| 6194 | { |
| 6195 | isc_result_t result; |
| 6196 | dns_dbnode_t *node = NULL; |
| 6197 | const char *directory = dns_zone_getkeydirectory(zone); |
| 6198 | |
| 6199 | CHECK(dns_db_findnode(db, dns_db_origin(db), false, &node)); |
| 6200 | memset(keys, 0, sizeof(*keys) * maxkeys); |
| 6201 | result = dns_dnssec_findzonekeys(db, ver, node, dns_db_origin(db), |
| 6202 | directory, now, mctx, maxkeys, keys, |
| 6203 | nkeys); |
| 6204 | if (result == ISC_R_NOTFOUND) |
| 6205 | result = ISC_R_SUCCESS; |
| 6206 | failure: |
| 6207 | if (node != NULL) |
| 6208 | dns_db_detachnode(db, &node); |
| 6209 | return (result); |
| 6210 | } |
| 6211 | |
| 6212 | static isc_result_t |
| 6213 | offline(dns_db_t *db, dns_dbversion_t *ver, dns__zonediff_t *zonediff, |
| 6214 | dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) |
| 6215 | { |
| 6216 | isc_result_t result; |
| 6217 | |
| 6218 | if ((rdata->flags & DNS_RDATA_OFFLINE) != 0) |
| 6219 | return (ISC_R_SUCCESS); |
| 6220 | result = update_one_rr(db, ver, zonediff->diff, DNS_DIFFOP_DELRESIGN, |
| 6221 | name, ttl, rdata); |
| 6222 | if (result != ISC_R_SUCCESS) |
| 6223 | return (result); |
| 6224 | rdata->flags |= DNS_RDATA_OFFLINE; |
| 6225 | result = update_one_rr(db, ver, zonediff->diff, DNS_DIFFOP_ADDRESIGN, |
| 6226 | name, ttl, rdata); |
| 6227 | zonediff->offline = true; |
| 6228 | return (result); |
| 6229 | } |
| 6230 | |
| 6231 | static void |
| 6232 | set_key_expiry_warning(dns_zone_t *zone, isc_stdtime_t when, isc_stdtime_t now) |
| 6233 | { |
| 6234 | unsigned int delta; |
| 6235 | char timebuf[80]; |
| 6236 | |
| 6237 | zone->key_expiry = when; |
| 6238 | if (when <= now) { |
| 6239 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6240 | "DNSKEY RRSIG(s) have expired" ); |
| 6241 | isc_time_settoepoch(&zone->keywarntime); |
| 6242 | } else if (when < now + 7 * 24 * 3600) { |
| 6243 | isc_time_t t; |
| 6244 | isc_time_set(&t, when, 0); |
| 6245 | isc_time_formattimestamp(&t, timebuf, 80); |
| 6246 | dns_zone_log(zone, ISC_LOG_WARNING, |
| 6247 | "DNSKEY RRSIG(s) will expire within 7 days: %s" , |
| 6248 | timebuf); |
| 6249 | delta = when - now; |
| 6250 | delta--; /* loop prevention */ |
| 6251 | delta /= 24 * 3600; /* to whole days */ |
| 6252 | delta *= 24 * 3600; /* to seconds */ |
| 6253 | isc_time_set(&zone->keywarntime, when - delta, 0); |
| 6254 | } else { |
| 6255 | isc_time_set(&zone->keywarntime, when - 7 * 24 * 3600, 0); |
| 6256 | isc_time_formattimestamp(&zone->keywarntime, timebuf, 80); |
| 6257 | dns_zone_log(zone, ISC_LOG_NOTICE, |
| 6258 | "setting keywarntime to %s" , timebuf); |
| 6259 | } |
| 6260 | } |
| 6261 | |
| 6262 | /* |
| 6263 | * Helper function to del_sigs(). We don't want to delete RRSIGs that |
| 6264 | * have no new key. |
| 6265 | */ |
| 6266 | static bool |
| 6267 | delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys, |
| 6268 | bool *warn) |
| 6269 | { |
| 6270 | unsigned int i = 0; |
| 6271 | bool have_ksk = false, have_zsk = false; |
| 6272 | bool have_pksk = false, have_pzsk = false; |
| 6273 | |
| 6274 | for (i = 0; i < nkeys; i++) { |
| 6275 | if (rrsig_ptr->algorithm != dst_key_alg(keys[i])) |
| 6276 | continue; |
| 6277 | if (dst_key_isprivate(keys[i])) { |
| 6278 | if (KSK(keys[i])) |
| 6279 | have_ksk = have_pksk = true; |
| 6280 | else |
| 6281 | have_zsk = have_pzsk = true; |
| 6282 | } else { |
| 6283 | if (KSK(keys[i])) |
| 6284 | have_ksk = true; |
| 6285 | else |
| 6286 | have_zsk = true; |
| 6287 | } |
| 6288 | } |
| 6289 | |
| 6290 | if (have_zsk && have_ksk && !have_pzsk) |
| 6291 | *warn = true; |
| 6292 | |
| 6293 | /* |
| 6294 | * It's okay to delete a signature if there is an active key |
| 6295 | * with the same algorithm to replace it. |
| 6296 | */ |
| 6297 | if (have_pksk || have_pzsk) |
| 6298 | return (true); |
| 6299 | |
| 6300 | /* |
| 6301 | * Failing that, it is *not* okay to delete a signature |
| 6302 | * if the associated public key is still in the DNSKEY RRset |
| 6303 | */ |
| 6304 | for (i = 0; i < nkeys; i++) { |
| 6305 | if ((rrsig_ptr->algorithm == dst_key_alg(keys[i])) && |
| 6306 | (rrsig_ptr->keyid == dst_key_id(keys[i]))) |
| 6307 | return (false); |
| 6308 | } |
| 6309 | |
| 6310 | /* |
| 6311 | * But if the key is gone, then go ahead. |
| 6312 | */ |
| 6313 | return (true); |
| 6314 | } |
| 6315 | |
| 6316 | /* |
| 6317 | * Delete expired RRsigs and any RRsigs we are about to re-sign. |
| 6318 | * See also update.c:del_keysigs(). |
| 6319 | */ |
| 6320 | static isc_result_t |
| 6321 | del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, |
| 6322 | dns_rdatatype_t type, dns__zonediff_t *zonediff, dst_key_t **keys, |
| 6323 | unsigned int nkeys, isc_stdtime_t now, bool incremental) |
| 6324 | { |
| 6325 | isc_result_t result; |
| 6326 | dns_dbnode_t *node = NULL; |
| 6327 | dns_rdataset_t rdataset; |
| 6328 | unsigned int i; |
| 6329 | dns_rdata_rrsig_t rrsig; |
| 6330 | bool found; |
| 6331 | int64_t timewarn = 0, timemaybe = 0; |
| 6332 | |
| 6333 | dns_rdataset_init(&rdataset); |
| 6334 | |
| 6335 | if (type == dns_rdatatype_nsec3) |
| 6336 | result = dns_db_findnsec3node(db, name, false, &node); |
| 6337 | else |
| 6338 | result = dns_db_findnode(db, name, false, &node); |
| 6339 | if (result == ISC_R_NOTFOUND) |
| 6340 | return (ISC_R_SUCCESS); |
| 6341 | if (result != ISC_R_SUCCESS) |
| 6342 | goto failure; |
| 6343 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig, type, |
| 6344 | (isc_stdtime_t) 0, &rdataset, NULL); |
| 6345 | dns_db_detachnode(db, &node); |
| 6346 | |
| 6347 | if (result == ISC_R_NOTFOUND) { |
| 6348 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 6349 | return (ISC_R_SUCCESS); |
| 6350 | } |
| 6351 | if (result != ISC_R_SUCCESS) { |
| 6352 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 6353 | goto failure; |
| 6354 | } |
| 6355 | |
| 6356 | for (result = dns_rdataset_first(&rdataset); |
| 6357 | result == ISC_R_SUCCESS; |
| 6358 | result = dns_rdataset_next(&rdataset)) { |
| 6359 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 6360 | |
| 6361 | dns_rdataset_current(&rdataset, &rdata); |
| 6362 | result = dns_rdata_tostruct(&rdata, &rrsig, NULL); |
| 6363 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 6364 | |
| 6365 | if (type != dns_rdatatype_dnskey) { |
| 6366 | bool warn = false, deleted = false; |
| 6367 | if (delsig_ok(&rrsig, keys, nkeys, &warn)) { |
| 6368 | result = update_one_rr(db, ver, zonediff->diff, |
| 6369 | DNS_DIFFOP_DELRESIGN, name, |
| 6370 | rdataset.ttl, &rdata); |
| 6371 | if (result != ISC_R_SUCCESS) |
| 6372 | break; |
| 6373 | deleted = true; |
| 6374 | } |
| 6375 | if (warn) { |
| 6376 | /* |
| 6377 | * At this point, we've got an RRSIG, |
| 6378 | * which is signed by an inactive key. |
| 6379 | * An administrator needs to provide a new |
| 6380 | * key/alg, but until that time, we want to |
| 6381 | * keep the old RRSIG. Marking the key as |
| 6382 | * offline will prevent us spinning waiting |
| 6383 | * for the private part. |
| 6384 | */ |
| 6385 | if (incremental && !deleted) { |
| 6386 | result = offline(db, ver, zonediff, |
| 6387 | name, rdataset.ttl, |
| 6388 | &rdata); |
| 6389 | if (result != ISC_R_SUCCESS) |
| 6390 | break; |
| 6391 | } |
| 6392 | |
| 6393 | /* |
| 6394 | * Log the key id and algorithm of |
| 6395 | * the inactive key with no replacement |
| 6396 | */ |
| 6397 | if (zone->log_key_expired_timer <= now) { |
| 6398 | char origin[DNS_NAME_FORMATSIZE]; |
| 6399 | char algbuf[DNS_NAME_FORMATSIZE]; |
| 6400 | dns_name_format(&zone->origin, origin, |
| 6401 | sizeof(origin)); |
| 6402 | dns_secalg_format(rrsig.algorithm, |
| 6403 | algbuf, |
| 6404 | sizeof(algbuf)); |
| 6405 | dns_zone_log(zone, ISC_LOG_WARNING, |
| 6406 | "Key %s/%s/%d " |
| 6407 | "missing or inactive " |
| 6408 | "and has no replacement: " |
| 6409 | "retaining signatures." , |
| 6410 | origin, algbuf, |
| 6411 | rrsig.keyid); |
| 6412 | zone->log_key_expired_timer = now + |
| 6413 | 3600; |
| 6414 | } |
| 6415 | } |
| 6416 | continue; |
| 6417 | } |
| 6418 | |
| 6419 | /* |
| 6420 | * RRSIG(DNSKEY) requires special processing. |
| 6421 | */ |
| 6422 | found = false; |
| 6423 | for (i = 0; i < nkeys; i++) { |
| 6424 | if (rrsig.algorithm == dst_key_alg(keys[i]) && |
| 6425 | rrsig.keyid == dst_key_id(keys[i])) { |
| 6426 | found = true; |
| 6427 | /* |
| 6428 | * Mark offline RRSIG(DNSKEY). |
| 6429 | * We want the earliest offline expire time |
| 6430 | * iff there is a new offline signature. |
| 6431 | */ |
| 6432 | if (!dst_key_inactive(keys[i]) && |
| 6433 | !dst_key_isprivate(keys[i])) |
| 6434 | { |
| 6435 | int64_t timeexpire = |
| 6436 | dns_time64_from32(rrsig.timeexpire); |
| 6437 | if (timewarn != 0 && |
| 6438 | timewarn > timeexpire) |
| 6439 | timewarn = timeexpire; |
| 6440 | if (rdata.flags & DNS_RDATA_OFFLINE) { |
| 6441 | if (timemaybe == 0 || |
| 6442 | timemaybe > timeexpire) |
| 6443 | timemaybe = timeexpire; |
| 6444 | break; |
| 6445 | } |
| 6446 | if (timewarn == 0) |
| 6447 | timewarn = timemaybe; |
| 6448 | if (timewarn == 0 || |
| 6449 | timewarn > timeexpire) |
| 6450 | timewarn = timeexpire; |
| 6451 | result = offline(db, ver, zonediff, |
| 6452 | name, rdataset.ttl, |
| 6453 | &rdata); |
| 6454 | break; |
| 6455 | } |
| 6456 | result = update_one_rr(db, ver, zonediff->diff, |
| 6457 | DNS_DIFFOP_DELRESIGN, |
| 6458 | name, rdataset.ttl, |
| 6459 | &rdata); |
| 6460 | break; |
| 6461 | } |
| 6462 | } |
| 6463 | |
| 6464 | /* |
| 6465 | * If there is not a matching DNSKEY then |
| 6466 | * delete the RRSIG. |
| 6467 | */ |
| 6468 | if (!found) |
| 6469 | result = update_one_rr(db, ver, zonediff->diff, |
| 6470 | DNS_DIFFOP_DELRESIGN, name, |
| 6471 | rdataset.ttl, &rdata); |
| 6472 | if (result != ISC_R_SUCCESS) |
| 6473 | break; |
| 6474 | } |
| 6475 | |
| 6476 | dns_rdataset_disassociate(&rdataset); |
| 6477 | if (result == ISC_R_NOMORE) |
| 6478 | result = ISC_R_SUCCESS; |
| 6479 | if (timewarn > 0) { |
| 6480 | isc_stdtime_t stdwarn = (isc_stdtime_t)timewarn; |
| 6481 | if (timewarn == stdwarn) { |
| 6482 | set_key_expiry_warning(zone, (isc_stdtime_t)timewarn, |
| 6483 | now); |
| 6484 | } else { |
| 6485 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6486 | "key expiry warning time out of range" ); |
| 6487 | } |
| 6488 | } |
| 6489 | failure: |
| 6490 | if (node != NULL) |
| 6491 | dns_db_detachnode(db, &node); |
| 6492 | return (result); |
| 6493 | } |
| 6494 | |
| 6495 | static isc_result_t |
| 6496 | add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, |
| 6497 | dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, |
| 6498 | unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, |
| 6499 | isc_stdtime_t expire, bool check_ksk, |
| 6500 | bool keyset_kskonly) |
| 6501 | { |
| 6502 | isc_result_t result; |
| 6503 | dns_dbnode_t *node = NULL; |
| 6504 | dns_rdataset_t rdataset; |
| 6505 | dns_rdata_t sig_rdata = DNS_RDATA_INIT; |
| 6506 | unsigned char data[1024]; /* XXX */ |
| 6507 | isc_buffer_t buffer; |
| 6508 | unsigned int i, j; |
| 6509 | |
| 6510 | dns_rdataset_init(&rdataset); |
| 6511 | isc_buffer_init(&buffer, data, sizeof(data)); |
| 6512 | |
| 6513 | if (type == dns_rdatatype_nsec3) |
| 6514 | result = dns_db_findnsec3node(db, name, false, &node); |
| 6515 | else |
| 6516 | result = dns_db_findnode(db, name, false, &node); |
| 6517 | if (result == ISC_R_NOTFOUND) |
| 6518 | return (ISC_R_SUCCESS); |
| 6519 | if (result != ISC_R_SUCCESS) |
| 6520 | goto failure; |
| 6521 | result = dns_db_findrdataset(db, node, ver, type, 0, |
| 6522 | (isc_stdtime_t) 0, &rdataset, NULL); |
| 6523 | dns_db_detachnode(db, &node); |
| 6524 | if (result == ISC_R_NOTFOUND) { |
| 6525 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 6526 | return (ISC_R_SUCCESS); |
| 6527 | } |
| 6528 | if (result != ISC_R_SUCCESS) { |
| 6529 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 6530 | goto failure; |
| 6531 | } |
| 6532 | |
| 6533 | for (i = 0; i < nkeys; i++) { |
| 6534 | bool both = false; |
| 6535 | |
| 6536 | if (!dst_key_isprivate(keys[i])) |
| 6537 | continue; |
| 6538 | if (dst_key_inactive(keys[i])) /* Should be redundant. */ |
| 6539 | continue; |
| 6540 | |
| 6541 | if (check_ksk && !REVOKE(keys[i])) { |
| 6542 | bool have_ksk, have_nonksk; |
| 6543 | if (KSK(keys[i])) { |
| 6544 | have_ksk = true; |
| 6545 | have_nonksk = false; |
| 6546 | } else { |
| 6547 | have_ksk = false; |
| 6548 | have_nonksk = true; |
| 6549 | } |
| 6550 | for (j = 0; j < nkeys; j++) { |
| 6551 | if (j == i || ALG(keys[i]) != ALG(keys[j])) |
| 6552 | continue; |
| 6553 | if (!dst_key_isprivate(keys[j])) |
| 6554 | continue; |
| 6555 | if (dst_key_inactive(keys[j])) /* SBR */ |
| 6556 | continue; |
| 6557 | if (REVOKE(keys[j])) |
| 6558 | continue; |
| 6559 | if (KSK(keys[j])) |
| 6560 | have_ksk = true; |
| 6561 | else |
| 6562 | have_nonksk = true; |
| 6563 | both = have_ksk && have_nonksk; |
| 6564 | if (both) |
| 6565 | break; |
| 6566 | } |
| 6567 | } |
| 6568 | if (both) { |
| 6569 | /* |
| 6570 | * CDS and CDNSKEY are signed with KSK (RFC 7344, 4.1). |
| 6571 | */ |
| 6572 | if (type == dns_rdatatype_dnskey || |
| 6573 | type == dns_rdatatype_cdnskey || |
| 6574 | type == dns_rdatatype_cds) |
| 6575 | { |
| 6576 | if (!KSK(keys[i]) && keyset_kskonly) |
| 6577 | continue; |
| 6578 | } else if (KSK(keys[i])) { |
| 6579 | continue; |
| 6580 | } |
| 6581 | } else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey) { |
| 6582 | continue; |
| 6583 | } |
| 6584 | |
| 6585 | /* Calculate the signature, creating a RRSIG RDATA. */ |
| 6586 | isc_buffer_clear(&buffer); |
| 6587 | CHECK(dns_dnssec_sign(name, &rdataset, keys[i], |
| 6588 | &inception, &expire, |
| 6589 | mctx, &buffer, &sig_rdata)); |
| 6590 | /* Update the database and journal with the RRSIG. */ |
| 6591 | /* XXX inefficient - will cause dataset merging */ |
| 6592 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, |
| 6593 | name, rdataset.ttl, &sig_rdata)); |
| 6594 | dns_rdata_reset(&sig_rdata); |
| 6595 | isc_buffer_init(&buffer, data, sizeof(data)); |
| 6596 | } |
| 6597 | |
| 6598 | failure: |
| 6599 | if (dns_rdataset_isassociated(&rdataset)) |
| 6600 | dns_rdataset_disassociate(&rdataset); |
| 6601 | if (node != NULL) |
| 6602 | dns_db_detachnode(db, &node); |
| 6603 | return (result); |
| 6604 | } |
| 6605 | |
| 6606 | static void |
| 6607 | zone_resigninc(dns_zone_t *zone) { |
| 6608 | const char *me = "zone_resigninc" ; |
| 6609 | dns_db_t *db = NULL; |
| 6610 | dns_dbversion_t *version = NULL; |
| 6611 | dns_diff_t _sig_diff; |
| 6612 | dns__zonediff_t zonediff; |
| 6613 | dns_fixedname_t fixed; |
| 6614 | dns_name_t *name; |
| 6615 | dns_rdataset_t rdataset; |
| 6616 | dns_rdatatype_t covers; |
| 6617 | dst_key_t *zone_keys[DNS_MAXZONEKEYS]; |
| 6618 | bool check_ksk, keyset_kskonly = false; |
| 6619 | isc_result_t result; |
| 6620 | isc_stdtime_t now, inception, soaexpire, expire, stop; |
| 6621 | uint32_t jitter, sigvalidityinterval; |
| 6622 | unsigned int i; |
| 6623 | unsigned int nkeys = 0; |
| 6624 | unsigned int resign; |
| 6625 | |
| 6626 | ENTER; |
| 6627 | |
| 6628 | dns_rdataset_init(&rdataset); |
| 6629 | dns_diff_init(zone->mctx, &_sig_diff); |
| 6630 | zonediff_init(&zonediff, &_sig_diff); |
| 6631 | |
| 6632 | /* |
| 6633 | * Zone is frozen or automatic resigning is disabled. |
| 6634 | * Pause for 5 minutes. |
| 6635 | */ |
| 6636 | if (zone->update_disabled || |
| 6637 | DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_NORESIGN)) |
| 6638 | { |
| 6639 | result = ISC_R_FAILURE; |
| 6640 | goto failure; |
| 6641 | } |
| 6642 | |
| 6643 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 6644 | dns_db_attach(zone->db, &db); |
| 6645 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 6646 | |
| 6647 | result = dns_db_newversion(db, &version); |
| 6648 | if (result != ISC_R_SUCCESS) { |
| 6649 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6650 | "zone_resigninc:dns_db_newversion -> %s" , |
| 6651 | dns_result_totext(result)); |
| 6652 | goto failure; |
| 6653 | } |
| 6654 | |
| 6655 | isc_stdtime_get(&now); |
| 6656 | |
| 6657 | result = dns__zone_findkeys(zone, db, version, now, zone->mctx, |
| 6658 | DNS_MAXZONEKEYS, zone_keys, &nkeys); |
| 6659 | if (result != ISC_R_SUCCESS) { |
| 6660 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6661 | "zone_resigninc:dns__zone_findkeys -> %s" , |
| 6662 | dns_result_totext(result)); |
| 6663 | goto failure; |
| 6664 | } |
| 6665 | |
| 6666 | sigvalidityinterval = zone->sigvalidityinterval; |
| 6667 | inception = now - 3600; /* Allow for clock skew. */ |
| 6668 | soaexpire = now + sigvalidityinterval; |
| 6669 | /* |
| 6670 | * Spread out signatures over time if they happen to be |
| 6671 | * clumped. We don't do this for each add_sigs() call as |
| 6672 | * we still want some clustering to occur. |
| 6673 | */ |
| 6674 | if (sigvalidityinterval >= 3600U) { |
| 6675 | if (sigvalidityinterval > 7200U) { |
| 6676 | jitter = isc_random_uniform(3600); |
| 6677 | } else { |
| 6678 | jitter = isc_random_uniform(1200); |
| 6679 | } |
| 6680 | expire = soaexpire - jitter - 1; |
| 6681 | } else { |
| 6682 | expire = soaexpire - 1; |
| 6683 | } |
| 6684 | stop = now + 5; |
| 6685 | |
| 6686 | check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); |
| 6687 | keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); |
| 6688 | |
| 6689 | name = dns_fixedname_initname(&fixed); |
| 6690 | result = dns_db_getsigningtime(db, &rdataset, name); |
| 6691 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { |
| 6692 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6693 | "zone_resigninc:dns_db_getsigningtime -> %s" , |
| 6694 | dns_result_totext(result)); |
| 6695 | } |
| 6696 | |
| 6697 | i = 0; |
| 6698 | while (result == ISC_R_SUCCESS) { |
| 6699 | resign = rdataset.resign - zone->sigresigninginterval; |
| 6700 | covers = rdataset.covers; |
| 6701 | dns_rdataset_disassociate(&rdataset); |
| 6702 | |
| 6703 | /* |
| 6704 | * Stop if we hit the SOA as that means we have walked the |
| 6705 | * entire zone. The SOA record should always be the most |
| 6706 | * recent signature. |
| 6707 | */ |
| 6708 | /* XXXMPA increase number of RRsets signed pre call */ |
| 6709 | if (covers == dns_rdatatype_soa || i++ > zone->signatures || |
| 6710 | resign > stop) |
| 6711 | break; |
| 6712 | |
| 6713 | result = del_sigs(zone, db, version, name, covers, &zonediff, |
| 6714 | zone_keys, nkeys, now, true); |
| 6715 | if (result != ISC_R_SUCCESS) { |
| 6716 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6717 | "zone_resigninc:del_sigs -> %s" , |
| 6718 | dns_result_totext(result)); |
| 6719 | break; |
| 6720 | } |
| 6721 | |
| 6722 | result = add_sigs(db, version, name, covers, zonediff.diff, |
| 6723 | zone_keys, nkeys, zone->mctx, inception, |
| 6724 | expire, check_ksk, keyset_kskonly); |
| 6725 | if (result != ISC_R_SUCCESS) { |
| 6726 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6727 | "zone_resigninc:add_sigs -> %s" , |
| 6728 | dns_result_totext(result)); |
| 6729 | break; |
| 6730 | } |
| 6731 | result = dns_db_getsigningtime(db, &rdataset, name); |
| 6732 | if (nkeys == 0 && result == ISC_R_NOTFOUND) { |
| 6733 | result = ISC_R_SUCCESS; |
| 6734 | break; |
| 6735 | } |
| 6736 | if (result != ISC_R_SUCCESS) |
| 6737 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6738 | "zone_resigninc:dns_db_getsigningtime -> %s" , |
| 6739 | dns_result_totext(result)); |
| 6740 | } |
| 6741 | |
| 6742 | if (result != ISC_R_NOMORE && result != ISC_R_SUCCESS) |
| 6743 | goto failure; |
| 6744 | |
| 6745 | result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, |
| 6746 | &zonediff, zone_keys, nkeys, now, true); |
| 6747 | if (result != ISC_R_SUCCESS) { |
| 6748 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6749 | "zone_resigninc:del_sigs -> %s" , |
| 6750 | dns_result_totext(result)); |
| 6751 | goto failure; |
| 6752 | } |
| 6753 | |
| 6754 | /* |
| 6755 | * Did we change anything in the zone? |
| 6756 | */ |
| 6757 | if (ISC_LIST_EMPTY(zonediff.diff->tuples)) { |
| 6758 | /* |
| 6759 | * Commit the changes if any key has been marked as offline. |
| 6760 | */ |
| 6761 | if (zonediff.offline) |
| 6762 | dns_db_closeversion(db, &version, true); |
| 6763 | goto failure; |
| 6764 | } |
| 6765 | |
| 6766 | /* Increment SOA serial if we have made changes */ |
| 6767 | result = update_soa_serial(db, version, zonediff.diff, zone->mctx, |
| 6768 | zone->updatemethod); |
| 6769 | if (result != ISC_R_SUCCESS) { |
| 6770 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6771 | "zone_resigninc:update_soa_serial -> %s" , |
| 6772 | dns_result_totext(result)); |
| 6773 | goto failure; |
| 6774 | } |
| 6775 | |
| 6776 | /* |
| 6777 | * Generate maximum life time signatures so that the above loop |
| 6778 | * termination is sensible. |
| 6779 | */ |
| 6780 | result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, |
| 6781 | zonediff.diff, zone_keys, nkeys, zone->mctx, |
| 6782 | inception, soaexpire, check_ksk, keyset_kskonly); |
| 6783 | if (result != ISC_R_SUCCESS) { |
| 6784 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 6785 | "zone_resigninc:add_sigs -> %s" , |
| 6786 | dns_result_totext(result)); |
| 6787 | goto failure; |
| 6788 | } |
| 6789 | |
| 6790 | /* Write changes to journal file. */ |
| 6791 | CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_resigninc" )); |
| 6792 | |
| 6793 | /* Everything has succeeded. Commit the changes. */ |
| 6794 | dns_db_closeversion(db, &version, true); |
| 6795 | |
| 6796 | failure: |
| 6797 | dns_diff_clear(&_sig_diff); |
| 6798 | for (i = 0; i < nkeys; i++) |
| 6799 | dst_key_free(&zone_keys[i]); |
| 6800 | if (version != NULL) { |
| 6801 | dns_db_closeversion(db, &version, false); |
| 6802 | dns_db_detach(&db); |
| 6803 | } else if (db != NULL) |
| 6804 | dns_db_detach(&db); |
| 6805 | if (result == ISC_R_SUCCESS) { |
| 6806 | set_resigntime(zone); |
| 6807 | LOCK_ZONE(zone); |
| 6808 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 6809 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 6810 | UNLOCK_ZONE(zone); |
| 6811 | } else { |
| 6812 | /* |
| 6813 | * Something failed. Retry in 5 minutes. |
| 6814 | */ |
| 6815 | isc_interval_t ival; |
| 6816 | isc_interval_set(&ival, 300, 0); |
| 6817 | isc_time_nowplusinterval(&zone->resigntime, &ival); |
| 6818 | } |
| 6819 | |
| 6820 | INSIST(version == NULL); |
| 6821 | } |
| 6822 | |
| 6823 | static isc_result_t |
| 6824 | next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname, |
| 6825 | dns_name_t *newname, bool bottom) |
| 6826 | { |
| 6827 | isc_result_t result; |
| 6828 | dns_dbiterator_t *dbit = NULL; |
| 6829 | dns_rdatasetiter_t *rdsit = NULL; |
| 6830 | dns_dbnode_t *node = NULL; |
| 6831 | |
| 6832 | CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit)); |
| 6833 | CHECK(dns_dbiterator_seek(dbit, oldname)); |
| 6834 | do { |
| 6835 | result = dns_dbiterator_next(dbit); |
| 6836 | if (result == ISC_R_NOMORE) |
| 6837 | CHECK(dns_dbiterator_first(dbit)); |
| 6838 | CHECK(dns_dbiterator_current(dbit, &node, newname)); |
| 6839 | if (bottom && dns_name_issubdomain(newname, oldname) && |
| 6840 | !dns_name_equal(newname, oldname)) { |
| 6841 | dns_db_detachnode(db, &node); |
| 6842 | continue; |
| 6843 | } |
| 6844 | /* |
| 6845 | * Is this node empty? |
| 6846 | */ |
| 6847 | CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsit)); |
| 6848 | result = dns_rdatasetiter_first(rdsit); |
| 6849 | dns_db_detachnode(db, &node); |
| 6850 | dns_rdatasetiter_destroy(&rdsit); |
| 6851 | if (result != ISC_R_NOMORE) |
| 6852 | break; |
| 6853 | } while (1); |
| 6854 | failure: |
| 6855 | if (node != NULL) |
| 6856 | dns_db_detachnode(db, &node); |
| 6857 | if (dbit != NULL) |
| 6858 | dns_dbiterator_destroy(&dbit); |
| 6859 | return (result); |
| 6860 | } |
| 6861 | |
| 6862 | static bool |
| 6863 | signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, |
| 6864 | dns_rdatatype_t type, dst_key_t *key) |
| 6865 | { |
| 6866 | isc_result_t result; |
| 6867 | dns_rdataset_t rdataset; |
| 6868 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 6869 | dns_rdata_rrsig_t rrsig; |
| 6870 | |
| 6871 | dns_rdataset_init(&rdataset); |
| 6872 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig, |
| 6873 | type, 0, &rdataset, NULL); |
| 6874 | if (result != ISC_R_SUCCESS) { |
| 6875 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 6876 | return (false); |
| 6877 | } |
| 6878 | for (result = dns_rdataset_first(&rdataset); |
| 6879 | result == ISC_R_SUCCESS; |
| 6880 | result = dns_rdataset_next(&rdataset)) { |
| 6881 | dns_rdataset_current(&rdataset, &rdata); |
| 6882 | result = dns_rdata_tostruct(&rdata, &rrsig, NULL); |
| 6883 | INSIST(result == ISC_R_SUCCESS); |
| 6884 | if (rrsig.algorithm == dst_key_alg(key) && |
| 6885 | rrsig.keyid == dst_key_id(key)) { |
| 6886 | dns_rdataset_disassociate(&rdataset); |
| 6887 | return (true); |
| 6888 | } |
| 6889 | dns_rdata_reset(&rdata); |
| 6890 | } |
| 6891 | dns_rdataset_disassociate(&rdataset); |
| 6892 | return (false); |
| 6893 | } |
| 6894 | |
| 6895 | static isc_result_t |
| 6896 | add_nsec(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, |
| 6897 | dns_dbnode_t *node, dns_ttl_t ttl, bool bottom, |
| 6898 | dns_diff_t *diff) |
| 6899 | { |
| 6900 | dns_fixedname_t fixed; |
| 6901 | dns_name_t *next; |
| 6902 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 6903 | isc_result_t result; |
| 6904 | unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE]; |
| 6905 | |
| 6906 | next = dns_fixedname_initname(&fixed); |
| 6907 | |
| 6908 | CHECK(next_active(db, version, name, next, bottom)); |
| 6909 | CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer, |
| 6910 | &rdata)); |
| 6911 | CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, ttl, |
| 6912 | &rdata)); |
| 6913 | failure: |
| 6914 | return (result); |
| 6915 | } |
| 6916 | |
| 6917 | static isc_result_t |
| 6918 | check_if_bottom_of_zone(dns_db_t *db, dns_dbnode_t *node, |
| 6919 | dns_dbversion_t *version, bool *is_bottom_of_zone) |
| 6920 | { |
| 6921 | isc_result_t result; |
| 6922 | dns_rdatasetiter_t *iterator = NULL; |
| 6923 | dns_rdataset_t rdataset; |
| 6924 | bool seen_soa = false, seen_ns = false, seen_dname = false; |
| 6925 | |
| 6926 | REQUIRE(is_bottom_of_zone != NULL); |
| 6927 | |
| 6928 | result = dns_db_allrdatasets(db, node, version, 0, &iterator); |
| 6929 | if (result != ISC_R_SUCCESS) { |
| 6930 | if (result == ISC_R_NOTFOUND) { |
| 6931 | result = ISC_R_SUCCESS; |
| 6932 | } |
| 6933 | return (result); |
| 6934 | } |
| 6935 | |
| 6936 | dns_rdataset_init(&rdataset); |
| 6937 | for (result = dns_rdatasetiter_first(iterator); |
| 6938 | result == ISC_R_SUCCESS; |
| 6939 | result = dns_rdatasetiter_next(iterator)) { |
| 6940 | dns_rdatasetiter_current(iterator, &rdataset); |
| 6941 | switch (rdataset.type) { |
| 6942 | case dns_rdatatype_soa: |
| 6943 | seen_soa = true; |
| 6944 | break; |
| 6945 | case dns_rdatatype_ns: |
| 6946 | seen_ns = true; |
| 6947 | break; |
| 6948 | case dns_rdatatype_dname: |
| 6949 | seen_dname = true; |
| 6950 | break; |
| 6951 | } |
| 6952 | dns_rdataset_disassociate(&rdataset); |
| 6953 | } |
| 6954 | if (result != ISC_R_NOMORE) { |
| 6955 | goto failure; |
| 6956 | } |
| 6957 | if ((seen_ns && !seen_soa) || seen_dname) { |
| 6958 | *is_bottom_of_zone = true; |
| 6959 | } |
| 6960 | result = ISC_R_SUCCESS; |
| 6961 | |
| 6962 | failure: |
| 6963 | dns_rdatasetiter_destroy(&iterator); |
| 6964 | |
| 6965 | return (result); |
| 6966 | } |
| 6967 | |
| 6968 | static isc_result_t |
| 6969 | sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, |
| 6970 | dns_dbversion_t *version, bool build_nsec3, |
| 6971 | bool build_nsec, dst_key_t *key, |
| 6972 | isc_stdtime_t inception, isc_stdtime_t expire, |
| 6973 | unsigned int minimum, bool is_ksk, |
| 6974 | bool keyset_kskonly, bool is_bottom_of_zone, |
| 6975 | dns_diff_t *diff, int32_t *signatures, isc_mem_t *mctx) |
| 6976 | { |
| 6977 | isc_result_t result; |
| 6978 | dns_rdatasetiter_t *iterator = NULL; |
| 6979 | dns_rdataset_t rdataset; |
| 6980 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 6981 | isc_buffer_t buffer; |
| 6982 | unsigned char data[1024]; |
| 6983 | bool seen_soa, seen_ns, seen_rr, seen_nsec, seen_nsec3, seen_ds; |
| 6984 | |
| 6985 | result = dns_db_allrdatasets(db, node, version, 0, &iterator); |
| 6986 | if (result != ISC_R_SUCCESS) { |
| 6987 | if (result == ISC_R_NOTFOUND) |
| 6988 | result = ISC_R_SUCCESS; |
| 6989 | return (result); |
| 6990 | } |
| 6991 | |
| 6992 | dns_rdataset_init(&rdataset); |
| 6993 | isc_buffer_init(&buffer, data, sizeof(data)); |
| 6994 | seen_rr = seen_soa = seen_ns = seen_nsec = seen_nsec3 = seen_ds = false; |
| 6995 | for (result = dns_rdatasetiter_first(iterator); |
| 6996 | result == ISC_R_SUCCESS; |
| 6997 | result = dns_rdatasetiter_next(iterator)) { |
| 6998 | dns_rdatasetiter_current(iterator, &rdataset); |
| 6999 | if (rdataset.type == dns_rdatatype_soa) |
| 7000 | seen_soa = true; |
| 7001 | else if (rdataset.type == dns_rdatatype_ns) |
| 7002 | seen_ns = true; |
| 7003 | else if (rdataset.type == dns_rdatatype_ds) |
| 7004 | seen_ds = true; |
| 7005 | else if (rdataset.type == dns_rdatatype_nsec) |
| 7006 | seen_nsec = true; |
| 7007 | else if (rdataset.type == dns_rdatatype_nsec3) |
| 7008 | seen_nsec3 = true; |
| 7009 | if (rdataset.type != dns_rdatatype_rrsig) |
| 7010 | seen_rr = true; |
| 7011 | dns_rdataset_disassociate(&rdataset); |
| 7012 | } |
| 7013 | if (result != ISC_R_NOMORE) |
| 7014 | goto failure; |
| 7015 | /* |
| 7016 | * Going from insecure to NSEC3. |
| 7017 | * Don't generate NSEC3 records for NSEC3 records. |
| 7018 | */ |
| 7019 | if (build_nsec3 && !seen_nsec3 && seen_rr) { |
| 7020 | bool unsecure = !seen_ds && seen_ns && !seen_soa; |
| 7021 | CHECK(dns_nsec3_addnsec3s(db, version, name, minimum, |
| 7022 | unsecure, diff)); |
| 7023 | (*signatures)--; |
| 7024 | } |
| 7025 | /* |
| 7026 | * Going from insecure to NSEC. |
| 7027 | * Don't generate NSEC records for NSEC3 records. |
| 7028 | */ |
| 7029 | if (build_nsec && !seen_nsec3 && !seen_nsec && seen_rr) { |
| 7030 | /* |
| 7031 | * Build a NSEC record except at the origin. |
| 7032 | */ |
| 7033 | if (!dns_name_equal(name, dns_db_origin(db))) { |
| 7034 | CHECK(add_nsec(db, version, name, node, minimum, |
| 7035 | is_bottom_of_zone, diff)); |
| 7036 | /* Count a NSEC generation as a signature generation. */ |
| 7037 | (*signatures)--; |
| 7038 | } |
| 7039 | } |
| 7040 | result = dns_rdatasetiter_first(iterator); |
| 7041 | while (result == ISC_R_SUCCESS) { |
| 7042 | dns_rdatasetiter_current(iterator, &rdataset); |
| 7043 | if (rdataset.type == dns_rdatatype_soa || |
| 7044 | rdataset.type == dns_rdatatype_rrsig) |
| 7045 | { |
| 7046 | goto next_rdataset; |
| 7047 | } |
| 7048 | if (rdataset.type == dns_rdatatype_dnskey || |
| 7049 | rdataset.type == dns_rdatatype_cdnskey || |
| 7050 | rdataset.type == dns_rdatatype_cds) |
| 7051 | { |
| 7052 | /* |
| 7053 | * CDS and CDNSKEY are signed with KSK like DNSKEY. |
| 7054 | * (RFC 7344, section 4.1 specifies that they must |
| 7055 | * be signed with a key in the current DS RRset, |
| 7056 | * which would only include KSK's.) |
| 7057 | */ |
| 7058 | if (!is_ksk && keyset_kskonly) { |
| 7059 | goto next_rdataset; |
| 7060 | } |
| 7061 | } else if (is_ksk) { |
| 7062 | goto next_rdataset; |
| 7063 | } |
| 7064 | if (seen_ns && !seen_soa && |
| 7065 | rdataset.type != dns_rdatatype_ds && |
| 7066 | rdataset.type != dns_rdatatype_nsec) |
| 7067 | { |
| 7068 | goto next_rdataset; |
| 7069 | } |
| 7070 | if (signed_with_key(db, node, version, rdataset.type, key)) { |
| 7071 | goto next_rdataset; |
| 7072 | } |
| 7073 | /* Calculate the signature, creating a RRSIG RDATA. */ |
| 7074 | isc_buffer_clear(&buffer); |
| 7075 | CHECK(dns_dnssec_sign(name, &rdataset, key, &inception, |
| 7076 | &expire, mctx, &buffer, &rdata)); |
| 7077 | /* Update the database and journal with the RRSIG. */ |
| 7078 | /* XXX inefficient - will cause dataset merging */ |
| 7079 | CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADDRESIGN, |
| 7080 | name, rdataset.ttl, &rdata)); |
| 7081 | dns_rdata_reset(&rdata); |
| 7082 | (*signatures)--; |
| 7083 | next_rdataset: |
| 7084 | dns_rdataset_disassociate(&rdataset); |
| 7085 | result = dns_rdatasetiter_next(iterator); |
| 7086 | } |
| 7087 | if (result == ISC_R_NOMORE) |
| 7088 | result = ISC_R_SUCCESS; |
| 7089 | failure: |
| 7090 | if (dns_rdataset_isassociated(&rdataset)) |
| 7091 | dns_rdataset_disassociate(&rdataset); |
| 7092 | if (iterator != NULL) |
| 7093 | dns_rdatasetiter_destroy(&iterator); |
| 7094 | return (result); |
| 7095 | } |
| 7096 | |
| 7097 | /* |
| 7098 | * If 'update_only' is set then don't create a NSEC RRset if it doesn't exist. |
| 7099 | */ |
| 7100 | static isc_result_t |
| 7101 | updatesecure(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, |
| 7102 | dns_ttl_t minimum, bool update_only, dns_diff_t *diff) |
| 7103 | { |
| 7104 | isc_result_t result; |
| 7105 | dns_rdataset_t rdataset; |
| 7106 | dns_dbnode_t *node = NULL; |
| 7107 | |
| 7108 | CHECK(dns_db_getoriginnode(db, &node)); |
| 7109 | if (update_only) { |
| 7110 | dns_rdataset_init(&rdataset); |
| 7111 | result = dns_db_findrdataset(db, node, version, |
| 7112 | dns_rdatatype_nsec, |
| 7113 | dns_rdatatype_none, |
| 7114 | 0, &rdataset, NULL); |
| 7115 | if (dns_rdataset_isassociated(&rdataset)) |
| 7116 | dns_rdataset_disassociate(&rdataset); |
| 7117 | if (result == ISC_R_NOTFOUND) |
| 7118 | goto success; |
| 7119 | if (result != ISC_R_SUCCESS) |
| 7120 | goto failure; |
| 7121 | } |
| 7122 | CHECK(delete_nsec(db, version, node, name, diff)); |
| 7123 | CHECK(add_nsec(db, version, name, node, minimum, false, diff)); |
| 7124 | success: |
| 7125 | result = ISC_R_SUCCESS; |
| 7126 | failure: |
| 7127 | if (node != NULL) |
| 7128 | dns_db_detachnode(db, &node); |
| 7129 | return (result); |
| 7130 | } |
| 7131 | |
| 7132 | static isc_result_t |
| 7133 | updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing, |
| 7134 | dns_dbversion_t *version, bool build_nsec3, |
| 7135 | dns_ttl_t minimum, dns_diff_t *diff) |
| 7136 | { |
| 7137 | isc_result_t result; |
| 7138 | dns_dbnode_t *node = NULL; |
| 7139 | dns_rdataset_t rdataset; |
| 7140 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 7141 | unsigned char data[5]; |
| 7142 | bool seen_done = false; |
| 7143 | bool have_rr = false; |
| 7144 | |
| 7145 | dns_rdataset_init(&rdataset); |
| 7146 | result = dns_db_getoriginnode(signing->db, &node); |
| 7147 | if (result != ISC_R_SUCCESS) |
| 7148 | goto failure; |
| 7149 | |
| 7150 | result = dns_db_findrdataset(signing->db, node, version, |
| 7151 | zone->privatetype, dns_rdatatype_none, |
| 7152 | 0, &rdataset, NULL); |
| 7153 | if (result == ISC_R_NOTFOUND) { |
| 7154 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 7155 | result = ISC_R_SUCCESS; |
| 7156 | goto failure; |
| 7157 | } |
| 7158 | if (result != ISC_R_SUCCESS) { |
| 7159 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 7160 | goto failure; |
| 7161 | } |
| 7162 | for (result = dns_rdataset_first(&rdataset); |
| 7163 | result == ISC_R_SUCCESS; |
| 7164 | result = dns_rdataset_next(&rdataset)) { |
| 7165 | dns_rdataset_current(&rdataset, &rdata); |
| 7166 | /* |
| 7167 | * If we don't match the algorithm or keyid skip the record. |
| 7168 | */ |
| 7169 | if (rdata.length != 5 || |
| 7170 | rdata.data[0] != signing->algorithm || |
| 7171 | rdata.data[1] != ((signing->keyid >> 8) & 0xff) || |
| 7172 | rdata.data[2] != (signing->keyid & 0xff)) { |
| 7173 | have_rr = true; |
| 7174 | dns_rdata_reset(&rdata); |
| 7175 | continue; |
| 7176 | } |
| 7177 | /* |
| 7178 | * We have a match. If we were signing (!signing->deleteit) |
| 7179 | * and we already have a record indicating that we have |
| 7180 | * finished signing (rdata.data[4] != 0) then keep it. |
| 7181 | * Otherwise it needs to be deleted as we have removed all |
| 7182 | * the signatures (signing->deleteit), so any record indicating |
| 7183 | * completion is now out of date, or we have finished signing |
| 7184 | * with the new record so we no longer need to remember that |
| 7185 | * we need to sign the zone with the matching key across a |
| 7186 | * nameserver re-start. |
| 7187 | */ |
| 7188 | if (!signing->deleteit && rdata.data[4] != 0) { |
| 7189 | seen_done = true; |
| 7190 | have_rr = true; |
| 7191 | } else |
| 7192 | CHECK(update_one_rr(signing->db, version, diff, |
| 7193 | DNS_DIFFOP_DEL, &zone->origin, |
| 7194 | rdataset.ttl, &rdata)); |
| 7195 | dns_rdata_reset(&rdata); |
| 7196 | } |
| 7197 | if (result == ISC_R_NOMORE) |
| 7198 | result = ISC_R_SUCCESS; |
| 7199 | if (!signing->deleteit && !seen_done) { |
| 7200 | /* |
| 7201 | * If we were signing then we need to indicate that we have |
| 7202 | * finished signing the zone with this key. If it is already |
| 7203 | * there we don't need to add it a second time. |
| 7204 | */ |
| 7205 | data[0] = signing->algorithm; |
| 7206 | data[1] = (signing->keyid >> 8) & 0xff; |
| 7207 | data[2] = signing->keyid & 0xff; |
| 7208 | data[3] = 0; |
| 7209 | data[4] = 1; |
| 7210 | rdata.length = sizeof(data); |
| 7211 | rdata.data = data; |
| 7212 | rdata.type = zone->privatetype; |
| 7213 | rdata.rdclass = dns_db_class(signing->db); |
| 7214 | CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD, |
| 7215 | &zone->origin, rdataset.ttl, &rdata)); |
| 7216 | } else if (!have_rr) { |
| 7217 | dns_name_t *origin = dns_db_origin(signing->db); |
| 7218 | /* |
| 7219 | * Rebuild the NSEC/NSEC3 record for the origin as we no |
| 7220 | * longer have any private records. |
| 7221 | */ |
| 7222 | if (build_nsec3) |
| 7223 | CHECK(dns_nsec3_addnsec3s(signing->db, version, origin, |
| 7224 | minimum, false, diff)); |
| 7225 | CHECK(updatesecure(signing->db, version, origin, minimum, |
| 7226 | true, diff)); |
| 7227 | } |
| 7228 | |
| 7229 | failure: |
| 7230 | if (dns_rdataset_isassociated(&rdataset)) |
| 7231 | dns_rdataset_disassociate(&rdataset); |
| 7232 | if (node != NULL) |
| 7233 | dns_db_detachnode(signing->db, &node); |
| 7234 | return (result); |
| 7235 | } |
| 7236 | |
| 7237 | /* |
| 7238 | * Called from zone_nsec3chain() in order to update zone records indicating |
| 7239 | * processing status of given NSEC3 chain: |
| 7240 | * |
| 7241 | * - If the supplied dns_nsec3chain_t structure has been fully processed |
| 7242 | * (which is indicated by "active" being set to false): |
| 7243 | * |
| 7244 | * - remove all NSEC3PARAM records matching the relevant NSEC3 chain, |
| 7245 | * |
| 7246 | * - remove all private-type records containing NSEC3PARAM RDATA matching |
| 7247 | * the relevant NSEC3 chain. |
| 7248 | * |
| 7249 | * - If the supplied dns_nsec3chain_t structure has not been fully processed |
| 7250 | * (which is indicated by "active" being set to true), only remove the |
| 7251 | * NSEC3PARAM record which matches the relevant NSEC3 chain and has the |
| 7252 | * "flags" field set to 0. |
| 7253 | * |
| 7254 | * - If given NSEC3 chain is being added, add an NSEC3PARAM record contained |
| 7255 | * in the relevant private-type record, but with the "flags" field set to |
| 7256 | * 0, indicating that this NSEC3 chain is now complete for this zone. |
| 7257 | * |
| 7258 | * Note that this function is called at different processing stages for NSEC3 |
| 7259 | * chain additions vs. removals and needs to handle all cases properly. |
| 7260 | */ |
| 7261 | static isc_result_t |
| 7262 | fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain, |
| 7263 | bool active, dns_rdatatype_t privatetype, |
| 7264 | dns_diff_t *diff) |
| 7265 | { |
| 7266 | dns_dbnode_t *node = NULL; |
| 7267 | dns_name_t *name = dns_db_origin(db); |
| 7268 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 7269 | dns_rdataset_t rdataset; |
| 7270 | dns_rdata_nsec3param_t nsec3param; |
| 7271 | isc_result_t result; |
| 7272 | isc_buffer_t buffer; |
| 7273 | unsigned char parambuf[DNS_NSEC3PARAM_BUFFERSIZE]; |
| 7274 | dns_ttl_t ttl = 0; |
| 7275 | bool nseconly = false, nsec3ok = false; |
| 7276 | |
| 7277 | dns_rdataset_init(&rdataset); |
| 7278 | |
| 7279 | result = dns_db_getoriginnode(db, &node); |
| 7280 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 7281 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, |
| 7282 | 0, 0, &rdataset, NULL); |
| 7283 | if (result == ISC_R_NOTFOUND) |
| 7284 | goto try_private; |
| 7285 | if (result != ISC_R_SUCCESS) |
| 7286 | goto failure; |
| 7287 | |
| 7288 | /* |
| 7289 | * Preserve the existing ttl. |
| 7290 | */ |
| 7291 | ttl = rdataset.ttl; |
| 7292 | |
| 7293 | /* |
| 7294 | * Delete all NSEC3PARAM records which match that in nsec3chain. |
| 7295 | */ |
| 7296 | for (result = dns_rdataset_first(&rdataset); |
| 7297 | result == ISC_R_SUCCESS; |
| 7298 | result = dns_rdataset_next(&rdataset)) { |
| 7299 | |
| 7300 | dns_rdataset_current(&rdataset, &rdata); |
| 7301 | CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); |
| 7302 | |
| 7303 | if (nsec3param.hash != chain->nsec3param.hash || |
| 7304 | (active && nsec3param.flags != 0) || |
| 7305 | nsec3param.iterations != chain->nsec3param.iterations || |
| 7306 | nsec3param.salt_length != chain->nsec3param.salt_length || |
| 7307 | memcmp(nsec3param.salt, chain->nsec3param.salt, |
| 7308 | nsec3param.salt_length)) { |
| 7309 | dns_rdata_reset(&rdata); |
| 7310 | continue; |
| 7311 | } |
| 7312 | |
| 7313 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, |
| 7314 | name, rdataset.ttl, &rdata)); |
| 7315 | dns_rdata_reset(&rdata); |
| 7316 | } |
| 7317 | if (result != ISC_R_NOMORE) |
| 7318 | goto failure; |
| 7319 | |
| 7320 | dns_rdataset_disassociate(&rdataset); |
| 7321 | |
| 7322 | try_private: |
| 7323 | |
| 7324 | if (active) |
| 7325 | goto add; |
| 7326 | |
| 7327 | result = dns_nsec_nseconly(db, ver, &nseconly); |
| 7328 | nsec3ok = (result == ISC_R_SUCCESS && !nseconly); |
| 7329 | |
| 7330 | /* |
| 7331 | * Delete all private records which match that in nsec3chain. |
| 7332 | */ |
| 7333 | result = dns_db_findrdataset(db, node, ver, privatetype, |
| 7334 | 0, 0, &rdataset, NULL); |
| 7335 | if (result == ISC_R_NOTFOUND) |
| 7336 | goto add; |
| 7337 | if (result != ISC_R_SUCCESS) |
| 7338 | goto failure; |
| 7339 | |
| 7340 | for (result = dns_rdataset_first(&rdataset); |
| 7341 | result == ISC_R_SUCCESS; |
| 7342 | result = dns_rdataset_next(&rdataset)) { |
| 7343 | dns_rdata_t private = DNS_RDATA_INIT; |
| 7344 | unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; |
| 7345 | |
| 7346 | dns_rdataset_current(&rdataset, &private); |
| 7347 | if (!dns_nsec3param_fromprivate(&private, &rdata, |
| 7348 | buf, sizeof(buf))) |
| 7349 | continue; |
| 7350 | CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); |
| 7351 | |
| 7352 | if ((!nsec3ok && |
| 7353 | (nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0) || |
| 7354 | nsec3param.hash != chain->nsec3param.hash || |
| 7355 | nsec3param.iterations != chain->nsec3param.iterations || |
| 7356 | nsec3param.salt_length != chain->nsec3param.salt_length || |
| 7357 | memcmp(nsec3param.salt, chain->nsec3param.salt, |
| 7358 | nsec3param.salt_length)) { |
| 7359 | dns_rdata_reset(&rdata); |
| 7360 | continue; |
| 7361 | } |
| 7362 | |
| 7363 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, |
| 7364 | name, rdataset.ttl, &private)); |
| 7365 | dns_rdata_reset(&rdata); |
| 7366 | } |
| 7367 | if (result != ISC_R_NOMORE) |
| 7368 | goto failure; |
| 7369 | |
| 7370 | add: |
| 7371 | if ((chain->nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) { |
| 7372 | result = ISC_R_SUCCESS; |
| 7373 | goto failure; |
| 7374 | } |
| 7375 | |
| 7376 | /* |
| 7377 | * Add a NSEC3PARAM record which matches that in nsec3chain but |
| 7378 | * with all flags bits cleared. |
| 7379 | * |
| 7380 | * Note: we do not clear chain->nsec3param.flags as this change |
| 7381 | * may be reversed. |
| 7382 | */ |
| 7383 | isc_buffer_init(&buffer, ¶mbuf, sizeof(parambuf)); |
| 7384 | CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), |
| 7385 | dns_rdatatype_nsec3param, |
| 7386 | &chain->nsec3param, &buffer)); |
| 7387 | rdata.data[1] = 0; /* Clear flag bits. */ |
| 7388 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, ttl, &rdata)); |
| 7389 | |
| 7390 | failure: |
| 7391 | dns_db_detachnode(db, &node); |
| 7392 | if (dns_rdataset_isassociated(&rdataset)) |
| 7393 | dns_rdataset_disassociate(&rdataset); |
| 7394 | return (result); |
| 7395 | } |
| 7396 | |
| 7397 | static isc_result_t |
| 7398 | delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, |
| 7399 | dns_name_t *name, dns_diff_t *diff) |
| 7400 | { |
| 7401 | dns_rdataset_t rdataset; |
| 7402 | isc_result_t result; |
| 7403 | |
| 7404 | dns_rdataset_init(&rdataset); |
| 7405 | |
| 7406 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, |
| 7407 | 0, 0, &rdataset, NULL); |
| 7408 | if (result == ISC_R_NOTFOUND) |
| 7409 | return (ISC_R_SUCCESS); |
| 7410 | if (result != ISC_R_SUCCESS) |
| 7411 | return (result); |
| 7412 | for (result = dns_rdataset_first(&rdataset); |
| 7413 | result == ISC_R_SUCCESS; |
| 7414 | result = dns_rdataset_next(&rdataset)) { |
| 7415 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 7416 | |
| 7417 | dns_rdataset_current(&rdataset, &rdata); |
| 7418 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name, |
| 7419 | rdataset.ttl, &rdata)); |
| 7420 | } |
| 7421 | if (result == ISC_R_NOMORE) |
| 7422 | result = ISC_R_SUCCESS; |
| 7423 | failure: |
| 7424 | dns_rdataset_disassociate(&rdataset); |
| 7425 | return (result); |
| 7426 | } |
| 7427 | |
| 7428 | static isc_result_t |
| 7429 | deletematchingnsec3(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, |
| 7430 | dns_name_t *name, const dns_rdata_nsec3param_t *param, |
| 7431 | dns_diff_t *diff) |
| 7432 | { |
| 7433 | dns_rdataset_t rdataset; |
| 7434 | dns_rdata_nsec3_t nsec3; |
| 7435 | isc_result_t result; |
| 7436 | |
| 7437 | dns_rdataset_init(&rdataset); |
| 7438 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, |
| 7439 | 0, 0, &rdataset, NULL); |
| 7440 | if (result == ISC_R_NOTFOUND) |
| 7441 | return (ISC_R_SUCCESS); |
| 7442 | if (result != ISC_R_SUCCESS) |
| 7443 | return (result); |
| 7444 | |
| 7445 | for (result = dns_rdataset_first(&rdataset); |
| 7446 | result == ISC_R_SUCCESS; |
| 7447 | result = dns_rdataset_next(&rdataset)) { |
| 7448 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 7449 | |
| 7450 | dns_rdataset_current(&rdataset, &rdata); |
| 7451 | CHECK(dns_rdata_tostruct(&rdata, &nsec3, NULL)); |
| 7452 | if (nsec3.hash != param->hash || |
| 7453 | nsec3.iterations != param->iterations || |
| 7454 | nsec3.salt_length != param->salt_length || |
| 7455 | memcmp(nsec3.salt, param->salt, nsec3.salt_length)) |
| 7456 | continue; |
| 7457 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name, |
| 7458 | rdataset.ttl, &rdata)); |
| 7459 | } |
| 7460 | if (result == ISC_R_NOMORE) |
| 7461 | result = ISC_R_SUCCESS; |
| 7462 | failure: |
| 7463 | dns_rdataset_disassociate(&rdataset); |
| 7464 | return (result); |
| 7465 | } |
| 7466 | |
| 7467 | static isc_result_t |
| 7468 | need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver, |
| 7469 | const dns_rdata_nsec3param_t *param, |
| 7470 | bool *answer) |
| 7471 | { |
| 7472 | dns_dbnode_t *node = NULL; |
| 7473 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 7474 | dns_rdata_nsec3param_t myparam; |
| 7475 | dns_rdataset_t rdataset; |
| 7476 | isc_result_t result; |
| 7477 | |
| 7478 | *answer = false; |
| 7479 | |
| 7480 | result = dns_db_getoriginnode(db, &node); |
| 7481 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 7482 | |
| 7483 | dns_rdataset_init(&rdataset); |
| 7484 | |
| 7485 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, |
| 7486 | 0, 0, &rdataset, NULL); |
| 7487 | if (result == ISC_R_SUCCESS) { |
| 7488 | dns_rdataset_disassociate(&rdataset); |
| 7489 | dns_db_detachnode(db, &node); |
| 7490 | return (result); |
| 7491 | } |
| 7492 | if (result != ISC_R_NOTFOUND) { |
| 7493 | dns_db_detachnode(db, &node); |
| 7494 | return (result); |
| 7495 | } |
| 7496 | |
| 7497 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, |
| 7498 | 0, 0, &rdataset, NULL); |
| 7499 | if (result == ISC_R_NOTFOUND) { |
| 7500 | *answer = true; |
| 7501 | dns_db_detachnode(db, &node); |
| 7502 | return (ISC_R_SUCCESS); |
| 7503 | } |
| 7504 | if (result != ISC_R_SUCCESS) { |
| 7505 | dns_db_detachnode(db, &node); |
| 7506 | return (result); |
| 7507 | } |
| 7508 | |
| 7509 | for (result = dns_rdataset_first(&rdataset); |
| 7510 | result == ISC_R_SUCCESS; |
| 7511 | result = dns_rdataset_next(&rdataset)) { |
| 7512 | dns_rdataset_current(&rdataset, &rdata); |
| 7513 | CHECK(dns_rdata_tostruct(&rdata, &myparam, NULL)); |
| 7514 | dns_rdata_reset(&rdata); |
| 7515 | /* |
| 7516 | * Ignore any NSEC3PARAM removals. |
| 7517 | */ |
| 7518 | if (NSEC3REMOVE(myparam.flags)) |
| 7519 | continue; |
| 7520 | /* |
| 7521 | * Ignore the chain that we are in the process of deleting. |
| 7522 | */ |
| 7523 | if (myparam.hash == param->hash && |
| 7524 | myparam.iterations == param->iterations && |
| 7525 | myparam.salt_length == param->salt_length && |
| 7526 | !memcmp(myparam.salt, param->salt, myparam.salt_length)) |
| 7527 | continue; |
| 7528 | /* |
| 7529 | * Found an active NSEC3 chain. |
| 7530 | */ |
| 7531 | break; |
| 7532 | } |
| 7533 | if (result == ISC_R_NOMORE) { |
| 7534 | *answer = true; |
| 7535 | result = ISC_R_SUCCESS; |
| 7536 | } |
| 7537 | |
| 7538 | failure: |
| 7539 | if (dns_rdataset_isassociated(&rdataset)) |
| 7540 | dns_rdataset_disassociate(&rdataset); |
| 7541 | dns_db_detachnode(db, &node); |
| 7542 | return (result); |
| 7543 | } |
| 7544 | |
| 7545 | /*% |
| 7546 | * Given a tuple which is part of a diff, return a pointer to the next tuple in |
| 7547 | * that diff which has the same name and type (or NULL if no such tuple is |
| 7548 | * found). |
| 7549 | */ |
| 7550 | static dns_difftuple_t * |
| 7551 | find_next_matching_tuple(dns_difftuple_t *cur) { |
| 7552 | dns_difftuple_t *next = cur; |
| 7553 | |
| 7554 | while ((next = ISC_LIST_NEXT(next, link)) != NULL) { |
| 7555 | if (cur->rdata.type == next->rdata.type && |
| 7556 | dns_name_equal(&cur->name, &next->name)) |
| 7557 | { |
| 7558 | return (next); |
| 7559 | } |
| 7560 | } |
| 7561 | |
| 7562 | return (NULL); |
| 7563 | } |
| 7564 | |
| 7565 | /*% |
| 7566 | * Remove all tuples with the same name and type as 'cur' from 'src' and append |
| 7567 | * them to 'dst'. |
| 7568 | */ |
| 7569 | static void |
| 7570 | move_matching_tuples(dns_difftuple_t *cur, dns_diff_t *src, dns_diff_t *dst) { |
| 7571 | do { |
| 7572 | dns_difftuple_t *next = find_next_matching_tuple(cur); |
| 7573 | ISC_LIST_UNLINK(src->tuples, cur, link); |
| 7574 | dns_diff_appendminimal(dst, &cur); |
| 7575 | cur = next; |
| 7576 | } while (cur != NULL); |
| 7577 | } |
| 7578 | |
| 7579 | /*% |
| 7580 | * Add/remove DNSSEC signatures for the list of "raw" zone changes supplied in |
| 7581 | * 'diff'. Gradually remove tuples from 'diff' and append them to 'zonediff' |
| 7582 | * along with tuples representing relevant signature changes. |
| 7583 | */ |
| 7584 | isc_result_t |
| 7585 | dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, |
| 7586 | dst_key_t *zone_keys[], unsigned int nkeys, |
| 7587 | dns_zone_t *zone, isc_stdtime_t inception, |
| 7588 | isc_stdtime_t expire, isc_stdtime_t keyexpire, |
| 7589 | isc_stdtime_t now, bool check_ksk, |
| 7590 | bool keyset_kskonly, dns__zonediff_t *zonediff) |
| 7591 | { |
| 7592 | dns_difftuple_t *tuple; |
| 7593 | isc_result_t result; |
| 7594 | |
| 7595 | while ((tuple = ISC_LIST_HEAD(diff->tuples)) != NULL) { |
| 7596 | isc_stdtime_t exp = expire; |
| 7597 | |
| 7598 | if (keyexpire != 0 && |
| 7599 | (tuple->rdata.type == dns_rdatatype_dnskey || |
| 7600 | tuple->rdata.type == dns_rdatatype_cdnskey || |
| 7601 | tuple->rdata.type == dns_rdatatype_cds)) |
| 7602 | { |
| 7603 | exp = keyexpire; |
| 7604 | } |
| 7605 | |
| 7606 | result = del_sigs(zone, db, version, &tuple->name, |
| 7607 | tuple->rdata.type, zonediff, |
| 7608 | zone_keys, nkeys, now, false); |
| 7609 | if (result != ISC_R_SUCCESS) { |
| 7610 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 7611 | "dns__zone_updatesigs:del_sigs -> %s" , |
| 7612 | dns_result_totext(result)); |
| 7613 | return (result); |
| 7614 | } |
| 7615 | result = add_sigs(db, version, &tuple->name, |
| 7616 | tuple->rdata.type, zonediff->diff, |
| 7617 | zone_keys, nkeys, zone->mctx, inception, |
| 7618 | exp, check_ksk, keyset_kskonly); |
| 7619 | if (result != ISC_R_SUCCESS) { |
| 7620 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 7621 | "dns__zone_updatesigs:add_sigs -> %s" , |
| 7622 | dns_result_totext(result)); |
| 7623 | return (result); |
| 7624 | } |
| 7625 | |
| 7626 | /* |
| 7627 | * Signature changes for all RRs with name tuple->name and type |
| 7628 | * tuple->rdata.type were appended to zonediff->diff. Now we |
| 7629 | * remove all the "raw" changes with the same name and type |
| 7630 | * from diff (so that they are not processed by this loop |
| 7631 | * again) and append them to zonediff so that they get applied. |
| 7632 | */ |
| 7633 | move_matching_tuples(tuple, diff, zonediff->diff); |
| 7634 | } |
| 7635 | return (ISC_R_SUCCESS); |
| 7636 | } |
| 7637 | |
| 7638 | /* |
| 7639 | * Incrementally build and sign a new NSEC3 chain using the parameters |
| 7640 | * requested. |
| 7641 | */ |
| 7642 | static void |
| 7643 | zone_nsec3chain(dns_zone_t *zone) { |
| 7644 | const char *me = "zone_nsec3chain" ; |
| 7645 | dns_db_t *db = NULL; |
| 7646 | dns_dbnode_t *node = NULL; |
| 7647 | dns_dbversion_t *version = NULL; |
| 7648 | dns_diff_t _sig_diff; |
| 7649 | dns_diff_t nsec_diff; |
| 7650 | dns_diff_t nsec3_diff; |
| 7651 | dns_diff_t param_diff; |
| 7652 | dns__zonediff_t zonediff; |
| 7653 | dns_fixedname_t fixed; |
| 7654 | dns_fixedname_t nextfixed; |
| 7655 | dns_name_t *name, *nextname; |
| 7656 | dns_rdataset_t rdataset; |
| 7657 | dns_nsec3chain_t *nsec3chain = NULL, *nextnsec3chain; |
| 7658 | dns_nsec3chainlist_t cleanup; |
| 7659 | dst_key_t *zone_keys[DNS_MAXZONEKEYS]; |
| 7660 | int32_t signatures; |
| 7661 | bool check_ksk, keyset_kskonly; |
| 7662 | bool delegation; |
| 7663 | bool first; |
| 7664 | isc_result_t result; |
| 7665 | isc_stdtime_t now, inception, soaexpire, expire; |
| 7666 | uint32_t jitter, sigvalidityinterval; |
| 7667 | unsigned int i; |
| 7668 | unsigned int nkeys = 0; |
| 7669 | uint32_t nodes; |
| 7670 | bool unsecure = false; |
| 7671 | bool seen_soa, seen_ns, seen_dname, seen_ds; |
| 7672 | bool seen_nsec, seen_nsec3, seen_rr; |
| 7673 | dns_rdatasetiter_t *iterator = NULL; |
| 7674 | bool buildnsecchain; |
| 7675 | bool updatensec = false; |
| 7676 | dns_rdatatype_t privatetype = zone->privatetype; |
| 7677 | |
| 7678 | ENTER; |
| 7679 | |
| 7680 | dns_rdataset_init(&rdataset); |
| 7681 | name = dns_fixedname_initname(&fixed); |
| 7682 | nextname = dns_fixedname_initname(&nextfixed); |
| 7683 | dns_diff_init(zone->mctx, ¶m_diff); |
| 7684 | dns_diff_init(zone->mctx, &nsec3_diff); |
| 7685 | dns_diff_init(zone->mctx, &nsec_diff); |
| 7686 | dns_diff_init(zone->mctx, &_sig_diff); |
| 7687 | zonediff_init(&zonediff, &_sig_diff); |
| 7688 | ISC_LIST_INIT(cleanup); |
| 7689 | |
| 7690 | /* |
| 7691 | * Updates are disabled. Pause for 5 minutes. |
| 7692 | */ |
| 7693 | if (zone->update_disabled) { |
| 7694 | result = ISC_R_FAILURE; |
| 7695 | goto failure; |
| 7696 | } |
| 7697 | |
| 7698 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 7699 | /* |
| 7700 | * This function is called when zone timer fires, after the latter gets |
| 7701 | * set by zone_addnsec3chain(). If the action triggering the call to |
| 7702 | * zone_addnsec3chain() is closely followed by a zone deletion request, |
| 7703 | * it might turn out that the timer thread will not be woken up until |
| 7704 | * after the zone is deleted by rmzone(), which calls dns_db_detach() |
| 7705 | * for zone->db, causing the latter to become NULL. Return immediately |
| 7706 | * if that happens. |
| 7707 | */ |
| 7708 | if (zone->db != NULL) { |
| 7709 | dns_db_attach(zone->db, &db); |
| 7710 | } |
| 7711 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 7712 | if (db == NULL) { |
| 7713 | return; |
| 7714 | } |
| 7715 | |
| 7716 | result = dns_db_newversion(db, &version); |
| 7717 | if (result != ISC_R_SUCCESS) { |
| 7718 | dnssec_log(zone, ISC_LOG_ERROR, |
| 7719 | "zone_nsec3chain:dns_db_newversion -> %s" , |
| 7720 | dns_result_totext(result)); |
| 7721 | goto failure; |
| 7722 | } |
| 7723 | |
| 7724 | isc_stdtime_get(&now); |
| 7725 | |
| 7726 | result = dns__zone_findkeys(zone, db, version, now, zone->mctx, |
| 7727 | DNS_MAXZONEKEYS, zone_keys, &nkeys); |
| 7728 | if (result != ISC_R_SUCCESS) { |
| 7729 | dnssec_log(zone, ISC_LOG_ERROR, |
| 7730 | "zone_nsec3chain:dns__zone_findkeys -> %s" , |
| 7731 | dns_result_totext(result)); |
| 7732 | goto failure; |
| 7733 | } |
| 7734 | |
| 7735 | sigvalidityinterval = dns_zone_getsigvalidityinterval(zone); |
| 7736 | inception = now - 3600; /* Allow for clock skew. */ |
| 7737 | soaexpire = now + sigvalidityinterval; |
| 7738 | |
| 7739 | /* |
| 7740 | * Spread out signatures over time if they happen to be |
| 7741 | * clumped. We don't do this for each add_sigs() call as |
| 7742 | * we still want some clustering to occur. |
| 7743 | */ |
| 7744 | if (sigvalidityinterval >= 3600U) { |
| 7745 | if (sigvalidityinterval > 7200U) { |
| 7746 | jitter = isc_random_uniform(3600); |
| 7747 | } else { |
| 7748 | jitter = isc_random_uniform(1200); |
| 7749 | } |
| 7750 | expire = soaexpire - jitter - 1; |
| 7751 | } else { |
| 7752 | expire = soaexpire - 1; |
| 7753 | } |
| 7754 | |
| 7755 | check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); |
| 7756 | keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); |
| 7757 | |
| 7758 | /* |
| 7759 | * We keep pulling nodes off each iterator in turn until |
| 7760 | * we have no more nodes to pull off or we reach the limits |
| 7761 | * for this quantum. |
| 7762 | */ |
| 7763 | nodes = zone->nodes; |
| 7764 | signatures = zone->signatures; |
| 7765 | LOCK_ZONE(zone); |
| 7766 | nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); |
| 7767 | UNLOCK_ZONE(zone); |
| 7768 | first = true; |
| 7769 | |
| 7770 | if (nsec3chain != NULL) { |
| 7771 | nsec3chain->save_delete_nsec = nsec3chain->delete_nsec; |
| 7772 | } |
| 7773 | /* |
| 7774 | * Generate new NSEC3 chains first. |
| 7775 | * |
| 7776 | * The following while loop iterates over nodes in the zone database, |
| 7777 | * updating the NSEC3 chain by calling dns_nsec3_addnsec3() for each of |
| 7778 | * them. Once all nodes are processed, the "delete_nsec" field is |
| 7779 | * consulted to check whether we are supposed to remove NSEC records |
| 7780 | * from the zone database; if so, the database iterator is reset to |
| 7781 | * point to the first node and the loop traverses all of them again, |
| 7782 | * this time removing NSEC records. If we hit a node which is obscured |
| 7783 | * by a delegation or a DNAME, nodes are skipped over until we find one |
| 7784 | * that is not obscured by the same obscuring name and then normal |
| 7785 | * processing is resumed. |
| 7786 | * |
| 7787 | * The above is repeated until all requested NSEC3 chain changes are |
| 7788 | * applied or when we reach the limits for this quantum, whichever |
| 7789 | * happens first. |
| 7790 | * |
| 7791 | * Note that the "signatures" variable is only used here to limit the |
| 7792 | * amount of work performed. Actual DNSSEC signatures are only |
| 7793 | * generated by dns__zone_updatesigs() calls later in this function. |
| 7794 | */ |
| 7795 | while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) { |
| 7796 | LOCK_ZONE(zone); |
| 7797 | nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link); |
| 7798 | |
| 7799 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 7800 | if (nsec3chain->done || nsec3chain->db != zone->db) { |
| 7801 | ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link); |
| 7802 | ISC_LIST_APPEND(cleanup, nsec3chain, link); |
| 7803 | } |
| 7804 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 7805 | UNLOCK_ZONE(zone); |
| 7806 | if (ISC_LIST_TAIL(cleanup) == nsec3chain) |
| 7807 | goto next_addchain; |
| 7808 | |
| 7809 | /* |
| 7810 | * Possible future db. |
| 7811 | */ |
| 7812 | if (nsec3chain->db != db) { |
| 7813 | goto next_addchain; |
| 7814 | } |
| 7815 | |
| 7816 | if (NSEC3REMOVE(nsec3chain->nsec3param.flags)) |
| 7817 | goto next_addchain; |
| 7818 | |
| 7819 | dns_dbiterator_current(nsec3chain->dbiterator, &node, name); |
| 7820 | |
| 7821 | if (nsec3chain->delete_nsec) { |
| 7822 | delegation = false; |
| 7823 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 7824 | CHECK(delete_nsec(db, version, node, name, &nsec_diff)); |
| 7825 | goto next_addnode; |
| 7826 | } |
| 7827 | /* |
| 7828 | * On the first pass we need to check if the current node |
| 7829 | * has not been obscured. |
| 7830 | */ |
| 7831 | delegation = false; |
| 7832 | unsecure = false; |
| 7833 | if (first) { |
| 7834 | dns_fixedname_t ffound; |
| 7835 | dns_name_t *found; |
| 7836 | found = dns_fixedname_initname(&ffound); |
| 7837 | result = dns_db_find(db, name, version, |
| 7838 | dns_rdatatype_soa, |
| 7839 | DNS_DBFIND_NOWILD, 0, NULL, found, |
| 7840 | NULL, NULL); |
| 7841 | if ((result == DNS_R_DELEGATION || |
| 7842 | result == DNS_R_DNAME) && |
| 7843 | !dns_name_equal(name, found)) { |
| 7844 | /* |
| 7845 | * Remember the obscuring name so that |
| 7846 | * we skip all obscured names. |
| 7847 | */ |
| 7848 | dns_name_copy(found, name, NULL); |
| 7849 | delegation = true; |
| 7850 | goto next_addnode; |
| 7851 | } |
| 7852 | } |
| 7853 | |
| 7854 | /* |
| 7855 | * Check to see if this is a bottom of zone node. |
| 7856 | */ |
| 7857 | result = dns_db_allrdatasets(db, node, version, 0, &iterator); |
| 7858 | if (result == ISC_R_NOTFOUND) { |
| 7859 | /* Empty node? */ |
| 7860 | goto next_addnode; |
| 7861 | } |
| 7862 | if (result != ISC_R_SUCCESS) { |
| 7863 | goto failure; |
| 7864 | } |
| 7865 | |
| 7866 | seen_soa = seen_ns = seen_dname = seen_ds = seen_nsec = false; |
| 7867 | for (result = dns_rdatasetiter_first(iterator); |
| 7868 | result == ISC_R_SUCCESS; |
| 7869 | result = dns_rdatasetiter_next(iterator)) |
| 7870 | { |
| 7871 | dns_rdatasetiter_current(iterator, &rdataset); |
| 7872 | INSIST(rdataset.type != dns_rdatatype_nsec3); |
| 7873 | if (rdataset.type == dns_rdatatype_soa) { |
| 7874 | seen_soa = true; |
| 7875 | } else if (rdataset.type == dns_rdatatype_ns) { |
| 7876 | seen_ns = true; |
| 7877 | } else if (rdataset.type == dns_rdatatype_dname) { |
| 7878 | seen_dname = true; |
| 7879 | } else if (rdataset.type == dns_rdatatype_ds) { |
| 7880 | seen_ds = true; |
| 7881 | } else if (rdataset.type == dns_rdatatype_nsec) { |
| 7882 | seen_nsec = true; |
| 7883 | } |
| 7884 | dns_rdataset_disassociate(&rdataset); |
| 7885 | } |
| 7886 | dns_rdatasetiter_destroy(&iterator); |
| 7887 | /* |
| 7888 | * Is there a NSEC chain than needs to be cleaned up? |
| 7889 | */ |
| 7890 | if (seen_nsec) { |
| 7891 | nsec3chain->seen_nsec = true; |
| 7892 | } |
| 7893 | if (seen_ns && !seen_soa && !seen_ds) { |
| 7894 | unsecure = true; |
| 7895 | } |
| 7896 | if ((seen_ns && !seen_soa) || seen_dname) { |
| 7897 | delegation = true; |
| 7898 | } |
| 7899 | |
| 7900 | /* |
| 7901 | * Process one node. |
| 7902 | */ |
| 7903 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 7904 | result = dns_nsec3_addnsec3(db, version, name, |
| 7905 | &nsec3chain->nsec3param, |
| 7906 | zone->minimum, unsecure, |
| 7907 | &nsec3_diff); |
| 7908 | if (result != ISC_R_SUCCESS) { |
| 7909 | dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" |
| 7910 | "dns_nsec3_addnsec3 -> %s" , |
| 7911 | dns_result_totext(result)); |
| 7912 | goto failure; |
| 7913 | } |
| 7914 | |
| 7915 | /* |
| 7916 | * Treat each call to dns_nsec3_addnsec3() as if it's cost is |
| 7917 | * two signatures. Additionally there will, in general, be |
| 7918 | * two signature generated below. |
| 7919 | * |
| 7920 | * If we are only changing the optout flag the cost is half |
| 7921 | * that of the cost of generating a completely new chain. |
| 7922 | */ |
| 7923 | signatures -= 4; |
| 7924 | |
| 7925 | /* |
| 7926 | * Go onto next node. |
| 7927 | */ |
| 7928 | next_addnode: |
| 7929 | first = false; |
| 7930 | dns_db_detachnode(db, &node); |
| 7931 | do { |
| 7932 | result = dns_dbiterator_next(nsec3chain->dbiterator); |
| 7933 | |
| 7934 | if (result == ISC_R_NOMORE && nsec3chain->delete_nsec) { |
| 7935 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 7936 | CHECK(fixup_nsec3param(db, version, nsec3chain, |
| 7937 | false, privatetype, |
| 7938 | ¶m_diff)); |
| 7939 | LOCK_ZONE(zone); |
| 7940 | ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, |
| 7941 | link); |
| 7942 | UNLOCK_ZONE(zone); |
| 7943 | ISC_LIST_APPEND(cleanup, nsec3chain, link); |
| 7944 | goto next_addchain; |
| 7945 | } |
| 7946 | if (result == ISC_R_NOMORE) { |
| 7947 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 7948 | if (nsec3chain->seen_nsec) { |
| 7949 | CHECK(fixup_nsec3param(db, version, |
| 7950 | nsec3chain, |
| 7951 | true, |
| 7952 | privatetype, |
| 7953 | ¶m_diff)); |
| 7954 | nsec3chain->delete_nsec = true; |
| 7955 | goto same_addchain; |
| 7956 | } |
| 7957 | CHECK(fixup_nsec3param(db, version, nsec3chain, |
| 7958 | false, privatetype, |
| 7959 | ¶m_diff)); |
| 7960 | LOCK_ZONE(zone); |
| 7961 | ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, |
| 7962 | link); |
| 7963 | UNLOCK_ZONE(zone); |
| 7964 | ISC_LIST_APPEND(cleanup, nsec3chain, link); |
| 7965 | goto next_addchain; |
| 7966 | } else if (result != ISC_R_SUCCESS) { |
| 7967 | dnssec_log(zone, ISC_LOG_ERROR, |
| 7968 | "zone_nsec3chain:" |
| 7969 | "dns_dbiterator_next -> %s" , |
| 7970 | dns_result_totext(result)); |
| 7971 | goto failure; |
| 7972 | } else if (delegation) { |
| 7973 | dns_dbiterator_current(nsec3chain->dbiterator, |
| 7974 | &node, nextname); |
| 7975 | dns_db_detachnode(db, &node); |
| 7976 | if (!dns_name_issubdomain(nextname, name)) |
| 7977 | break; |
| 7978 | } else { |
| 7979 | break; |
| 7980 | } |
| 7981 | } while (1); |
| 7982 | continue; |
| 7983 | |
| 7984 | same_addchain: |
| 7985 | CHECK(dns_dbiterator_first(nsec3chain->dbiterator)); |
| 7986 | first = true; |
| 7987 | continue; |
| 7988 | |
| 7989 | next_addchain: |
| 7990 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 7991 | nsec3chain = nextnsec3chain; |
| 7992 | first = true; |
| 7993 | if (nsec3chain != NULL) { |
| 7994 | nsec3chain->save_delete_nsec = nsec3chain->delete_nsec; |
| 7995 | } |
| 7996 | } |
| 7997 | |
| 7998 | if (nsec3chain != NULL) { |
| 7999 | goto skip_removals; |
| 8000 | } |
| 8001 | |
| 8002 | /* |
| 8003 | * Process removals. |
| 8004 | * |
| 8005 | * This is a counterpart of the above while loop which takes care of |
| 8006 | * removing an NSEC3 chain. It starts with determining whether the |
| 8007 | * zone needs to switch from NSEC3 to NSEC; if so, it first builds an |
| 8008 | * NSEC chain by iterating over all nodes in the zone database and only |
| 8009 | * then goes on to remove NSEC3 records be iterating over all nodes |
| 8010 | * again and calling deletematchingnsec3() for each of them; otherwise, |
| 8011 | * it starts removing NSEC3 records immediately. Rules for processing |
| 8012 | * obscured nodes and interrupting work are the same as for the while |
| 8013 | * loop above. |
| 8014 | */ |
| 8015 | LOCK_ZONE(zone); |
| 8016 | nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); |
| 8017 | UNLOCK_ZONE(zone); |
| 8018 | first = true; |
| 8019 | buildnsecchain = false; |
| 8020 | while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) { |
| 8021 | LOCK_ZONE(zone); |
| 8022 | nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link); |
| 8023 | UNLOCK_ZONE(zone); |
| 8024 | |
| 8025 | if (nsec3chain->db != db) { |
| 8026 | goto next_removechain; |
| 8027 | } |
| 8028 | |
| 8029 | if (!NSEC3REMOVE(nsec3chain->nsec3param.flags)) { |
| 8030 | goto next_removechain; |
| 8031 | } |
| 8032 | |
| 8033 | /* |
| 8034 | * Work out if we need to build a NSEC chain as a consequence |
| 8035 | * of removing this NSEC3 chain. |
| 8036 | */ |
| 8037 | if (first && !updatensec && |
| 8038 | (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0) |
| 8039 | { |
| 8040 | result = need_nsec_chain(db, version, |
| 8041 | &nsec3chain->nsec3param, |
| 8042 | &buildnsecchain); |
| 8043 | if (result != ISC_R_SUCCESS) { |
| 8044 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8045 | "zone_nsec3chain:" |
| 8046 | "need_nsec_chain -> %s" , |
| 8047 | dns_result_totext(result)); |
| 8048 | goto failure; |
| 8049 | } |
| 8050 | } |
| 8051 | |
| 8052 | if (first) { |
| 8053 | dnssec_log(zone, ISC_LOG_DEBUG(3), |
| 8054 | "zone_nsec3chain:buildnsecchain = %u\n" , |
| 8055 | buildnsecchain); |
| 8056 | } |
| 8057 | |
| 8058 | dns_dbiterator_current(nsec3chain->dbiterator, &node, name); |
| 8059 | delegation = false; |
| 8060 | |
| 8061 | if (!buildnsecchain) { |
| 8062 | /* |
| 8063 | * Delete the NSEC3PARAM record matching this chain. |
| 8064 | */ |
| 8065 | if (first) { |
| 8066 | result = fixup_nsec3param(db, version, |
| 8067 | nsec3chain, |
| 8068 | true, privatetype, |
| 8069 | ¶m_diff); |
| 8070 | if (result != ISC_R_SUCCESS) { |
| 8071 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8072 | "zone_nsec3chain:" |
| 8073 | "fixup_nsec3param -> %s" , |
| 8074 | dns_result_totext(result)); |
| 8075 | goto failure; |
| 8076 | } |
| 8077 | } |
| 8078 | |
| 8079 | /* |
| 8080 | * Delete the NSEC3 records. |
| 8081 | */ |
| 8082 | result = deletematchingnsec3(db, version, node, name, |
| 8083 | &nsec3chain->nsec3param, |
| 8084 | &nsec3_diff); |
| 8085 | if (result != ISC_R_SUCCESS) { |
| 8086 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8087 | "zone_nsec3chain:" |
| 8088 | "deletematchingnsec3 -> %s" , |
| 8089 | dns_result_totext(result)); |
| 8090 | goto failure; |
| 8091 | } |
| 8092 | goto next_removenode; |
| 8093 | } |
| 8094 | |
| 8095 | if (first) { |
| 8096 | dns_fixedname_t ffound; |
| 8097 | dns_name_t *found; |
| 8098 | found = dns_fixedname_initname(&ffound); |
| 8099 | result = dns_db_find(db, name, version, |
| 8100 | dns_rdatatype_soa, |
| 8101 | DNS_DBFIND_NOWILD, 0, NULL, found, |
| 8102 | NULL, NULL); |
| 8103 | if ((result == DNS_R_DELEGATION || |
| 8104 | result == DNS_R_DNAME) && |
| 8105 | !dns_name_equal(name, found)) |
| 8106 | { |
| 8107 | /* |
| 8108 | * Remember the obscuring name so that |
| 8109 | * we skip all obscured names. |
| 8110 | */ |
| 8111 | dns_name_copy(found, name, NULL); |
| 8112 | delegation = true; |
| 8113 | goto next_removenode; |
| 8114 | } |
| 8115 | } |
| 8116 | |
| 8117 | /* |
| 8118 | * Check to see if this is a bottom of zone node. |
| 8119 | */ |
| 8120 | result = dns_db_allrdatasets(db, node, version, 0, &iterator); |
| 8121 | if (result == ISC_R_NOTFOUND) { |
| 8122 | /* Empty node? */ |
| 8123 | goto next_removenode; |
| 8124 | } |
| 8125 | if (result != ISC_R_SUCCESS) { |
| 8126 | goto failure; |
| 8127 | } |
| 8128 | |
| 8129 | seen_soa = seen_ns = seen_dname = seen_nsec3 = |
| 8130 | seen_nsec = seen_rr = false; |
| 8131 | for (result = dns_rdatasetiter_first(iterator); |
| 8132 | result == ISC_R_SUCCESS; |
| 8133 | result = dns_rdatasetiter_next(iterator)) |
| 8134 | { |
| 8135 | dns_rdatasetiter_current(iterator, &rdataset); |
| 8136 | if (rdataset.type == dns_rdatatype_soa) { |
| 8137 | seen_soa = true; |
| 8138 | } else if (rdataset.type == dns_rdatatype_ns) { |
| 8139 | seen_ns = true; |
| 8140 | } else if (rdataset.type == dns_rdatatype_dname) { |
| 8141 | seen_dname = true; |
| 8142 | } else if (rdataset.type == dns_rdatatype_nsec) { |
| 8143 | seen_nsec = true; |
| 8144 | } else if (rdataset.type == dns_rdatatype_nsec3) { |
| 8145 | seen_nsec3 = true; |
| 8146 | } else if (rdataset.type != dns_rdatatype_rrsig) { |
| 8147 | seen_rr = true; |
| 8148 | } |
| 8149 | dns_rdataset_disassociate(&rdataset); |
| 8150 | } |
| 8151 | dns_rdatasetiter_destroy(&iterator); |
| 8152 | |
| 8153 | if (!seen_rr || seen_nsec3 || seen_nsec) { |
| 8154 | goto next_removenode; |
| 8155 | } |
| 8156 | if ((seen_ns && !seen_soa) || seen_dname) { |
| 8157 | delegation = true; |
| 8158 | } |
| 8159 | |
| 8160 | /* |
| 8161 | * Add a NSEC record except at the origin. |
| 8162 | */ |
| 8163 | if (!dns_name_equal(name, dns_db_origin(db))) { |
| 8164 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8165 | CHECK(add_nsec(db, version, name, node, zone->minimum, |
| 8166 | delegation, &nsec_diff)); |
| 8167 | signatures--; |
| 8168 | } |
| 8169 | |
| 8170 | next_removenode: |
| 8171 | first = false; |
| 8172 | dns_db_detachnode(db, &node); |
| 8173 | do { |
| 8174 | result = dns_dbiterator_next(nsec3chain->dbiterator); |
| 8175 | if (result == ISC_R_NOMORE && buildnsecchain) { |
| 8176 | /* |
| 8177 | * The NSEC chain should now be built. |
| 8178 | * We can now remove the NSEC3 chain. |
| 8179 | */ |
| 8180 | updatensec = true; |
| 8181 | goto same_removechain; |
| 8182 | } |
| 8183 | if (result == ISC_R_NOMORE) { |
| 8184 | LOCK_ZONE(zone); |
| 8185 | ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, |
| 8186 | link); |
| 8187 | UNLOCK_ZONE(zone); |
| 8188 | ISC_LIST_APPEND(cleanup, nsec3chain, link); |
| 8189 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8190 | result = fixup_nsec3param(db, version, |
| 8191 | nsec3chain, false, |
| 8192 | privatetype, |
| 8193 | ¶m_diff); |
| 8194 | if (result != ISC_R_SUCCESS) { |
| 8195 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8196 | "zone_nsec3chain:" |
| 8197 | "fixup_nsec3param -> %s" , |
| 8198 | dns_result_totext(result)); |
| 8199 | goto failure; |
| 8200 | } |
| 8201 | goto next_removechain; |
| 8202 | } else if (result != ISC_R_SUCCESS) { |
| 8203 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8204 | "zone_nsec3chain:" |
| 8205 | "dns_dbiterator_next -> %s" , |
| 8206 | dns_result_totext(result)); |
| 8207 | goto failure; |
| 8208 | } else if (delegation) { |
| 8209 | dns_dbiterator_current(nsec3chain->dbiterator, |
| 8210 | &node, nextname); |
| 8211 | dns_db_detachnode(db, &node); |
| 8212 | if (!dns_name_issubdomain(nextname, name)) { |
| 8213 | break; |
| 8214 | } |
| 8215 | } else { |
| 8216 | break; |
| 8217 | } |
| 8218 | } while (1); |
| 8219 | continue; |
| 8220 | |
| 8221 | same_removechain: |
| 8222 | CHECK(dns_dbiterator_first(nsec3chain->dbiterator)); |
| 8223 | buildnsecchain = false; |
| 8224 | first = true; |
| 8225 | continue; |
| 8226 | |
| 8227 | next_removechain: |
| 8228 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8229 | nsec3chain = nextnsec3chain; |
| 8230 | first = true; |
| 8231 | } |
| 8232 | |
| 8233 | skip_removals: |
| 8234 | /* |
| 8235 | * We may need to update the NSEC/NSEC3 records for the zone apex. |
| 8236 | */ |
| 8237 | if (!ISC_LIST_EMPTY(param_diff.tuples)) { |
| 8238 | bool rebuild_nsec = false, |
| 8239 | rebuild_nsec3 = false; |
| 8240 | result = dns_db_getoriginnode(db, &node); |
| 8241 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 8242 | result = dns_db_allrdatasets(db, node, version, 0, &iterator); |
| 8243 | if (result != ISC_R_SUCCESS) { |
| 8244 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8245 | "zone_nsec3chain:dns_db_allrdatasets -> %s" , |
| 8246 | dns_result_totext(result)); |
| 8247 | goto failure; |
| 8248 | } |
| 8249 | for (result = dns_rdatasetiter_first(iterator); |
| 8250 | result == ISC_R_SUCCESS; |
| 8251 | result = dns_rdatasetiter_next(iterator)) |
| 8252 | { |
| 8253 | dns_rdatasetiter_current(iterator, &rdataset); |
| 8254 | if (rdataset.type == dns_rdatatype_nsec) { |
| 8255 | rebuild_nsec = true; |
| 8256 | } else if (rdataset.type == dns_rdatatype_nsec3param) { |
| 8257 | rebuild_nsec3 = true; |
| 8258 | } |
| 8259 | dns_rdataset_disassociate(&rdataset); |
| 8260 | } |
| 8261 | dns_rdatasetiter_destroy(&iterator); |
| 8262 | dns_db_detachnode(db, &node); |
| 8263 | |
| 8264 | if (rebuild_nsec) { |
| 8265 | if (nsec3chain != NULL) { |
| 8266 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8267 | } |
| 8268 | |
| 8269 | result = updatesecure(db, version, &zone->origin, |
| 8270 | zone->minimum, true, |
| 8271 | &nsec_diff); |
| 8272 | if (result != ISC_R_SUCCESS) { |
| 8273 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8274 | "zone_nsec3chain:updatesecure -> %s" , |
| 8275 | dns_result_totext(result)); |
| 8276 | goto failure; |
| 8277 | } |
| 8278 | } |
| 8279 | |
| 8280 | if (rebuild_nsec3) { |
| 8281 | if (nsec3chain != NULL) { |
| 8282 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8283 | } |
| 8284 | |
| 8285 | result = dns_nsec3_addnsec3s(db, version, |
| 8286 | dns_db_origin(db), |
| 8287 | zone->minimum, false, |
| 8288 | &nsec3_diff); |
| 8289 | if (result != ISC_R_SUCCESS) { |
| 8290 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8291 | "zone_nsec3chain:" |
| 8292 | "dns_nsec3_addnsec3s -> %s" , |
| 8293 | dns_result_totext(result)); |
| 8294 | goto failure; |
| 8295 | } |
| 8296 | } |
| 8297 | } |
| 8298 | |
| 8299 | /* |
| 8300 | * Add / update signatures for the NSEC3 records. |
| 8301 | */ |
| 8302 | if (nsec3chain != NULL) { |
| 8303 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8304 | } |
| 8305 | result = dns__zone_updatesigs(&nsec3_diff, db, version, zone_keys, |
| 8306 | nkeys, zone, inception, expire, 0, now, |
| 8307 | check_ksk, keyset_kskonly, &zonediff); |
| 8308 | if (result != ISC_R_SUCCESS) { |
| 8309 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8310 | "zone_nsec3chain:dns__zone_updatesigs -> %s" , |
| 8311 | dns_result_totext(result)); |
| 8312 | goto failure; |
| 8313 | } |
| 8314 | |
| 8315 | /* |
| 8316 | * We have changed the NSEC3PARAM or private RRsets |
| 8317 | * above so we need to update the signatures. |
| 8318 | */ |
| 8319 | result = dns__zone_updatesigs(¶m_diff, db, version, zone_keys, |
| 8320 | nkeys, zone, inception, expire, 0, now, |
| 8321 | check_ksk, keyset_kskonly, &zonediff); |
| 8322 | if (result != ISC_R_SUCCESS) { |
| 8323 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8324 | "zone_nsec3chain:dns__zone_updatesigs -> %s" , |
| 8325 | dns_result_totext(result)); |
| 8326 | goto failure; |
| 8327 | } |
| 8328 | |
| 8329 | if (updatensec) { |
| 8330 | result = updatesecure(db, version, &zone->origin, |
| 8331 | zone->minimum, false, &nsec_diff); |
| 8332 | if (result != ISC_R_SUCCESS) { |
| 8333 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8334 | "zone_nsec3chain:updatesecure -> %s" , |
| 8335 | dns_result_totext(result)); |
| 8336 | goto failure; |
| 8337 | } |
| 8338 | } |
| 8339 | |
| 8340 | result = dns__zone_updatesigs(&nsec_diff, db, version, zone_keys, |
| 8341 | nkeys, zone, inception, expire, 0, now, |
| 8342 | check_ksk, keyset_kskonly, &zonediff); |
| 8343 | if (result != ISC_R_SUCCESS) { |
| 8344 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8345 | "zone_nsec3chain:dns__zone_updatesigs -> %s" , |
| 8346 | dns_result_totext(result)); |
| 8347 | goto failure; |
| 8348 | } |
| 8349 | |
| 8350 | /* |
| 8351 | * If we made no effective changes to the zone then we can just |
| 8352 | * cleanup otherwise we need to increment the serial. |
| 8353 | */ |
| 8354 | if (ISC_LIST_EMPTY(zonediff.diff->tuples)) { |
| 8355 | /* |
| 8356 | * No need to call dns_db_closeversion() here as it is |
| 8357 | * called with commit = true below. |
| 8358 | */ |
| 8359 | goto done; |
| 8360 | } |
| 8361 | |
| 8362 | result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, |
| 8363 | &zonediff, zone_keys, nkeys, now, false); |
| 8364 | if (result != ISC_R_SUCCESS) { |
| 8365 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8366 | "zone_nsec3chain:del_sigs -> %s" , |
| 8367 | dns_result_totext(result)); |
| 8368 | goto failure; |
| 8369 | } |
| 8370 | |
| 8371 | result = update_soa_serial(db, version, zonediff.diff, zone->mctx, |
| 8372 | zone->updatemethod); |
| 8373 | if (result != ISC_R_SUCCESS) { |
| 8374 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8375 | "zone_nsec3chain:update_soa_serial -> %s" , |
| 8376 | dns_result_totext(result)); |
| 8377 | goto failure; |
| 8378 | } |
| 8379 | |
| 8380 | result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, |
| 8381 | zonediff.diff, zone_keys, nkeys, zone->mctx, |
| 8382 | inception, soaexpire, check_ksk, keyset_kskonly); |
| 8383 | if (result != ISC_R_SUCCESS) { |
| 8384 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8385 | "zone_nsec3chain:add_sigs -> %s" , |
| 8386 | dns_result_totext(result)); |
| 8387 | goto failure; |
| 8388 | } |
| 8389 | |
| 8390 | /* Write changes to journal file. */ |
| 8391 | CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_nsec3chain" )); |
| 8392 | |
| 8393 | LOCK_ZONE(zone); |
| 8394 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 8395 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 8396 | UNLOCK_ZONE(zone); |
| 8397 | |
| 8398 | done: |
| 8399 | /* |
| 8400 | * Pause all iterators so that dns_db_closeversion() can succeed. |
| 8401 | */ |
| 8402 | LOCK_ZONE(zone); |
| 8403 | for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); |
| 8404 | nsec3chain != NULL; |
| 8405 | nsec3chain = ISC_LIST_NEXT(nsec3chain, link)) |
| 8406 | { |
| 8407 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8408 | } |
| 8409 | UNLOCK_ZONE(zone); |
| 8410 | |
| 8411 | /* |
| 8412 | * Everything has succeeded. Commit the changes. |
| 8413 | * Unconditionally commit as zonediff.offline not checked above. |
| 8414 | */ |
| 8415 | dns_db_closeversion(db, &version, true); |
| 8416 | |
| 8417 | /* |
| 8418 | * Everything succeeded so we can clean these up now. |
| 8419 | */ |
| 8420 | nsec3chain = ISC_LIST_HEAD(cleanup); |
| 8421 | while (nsec3chain != NULL) { |
| 8422 | ISC_LIST_UNLINK(cleanup, nsec3chain, link); |
| 8423 | dns_db_detach(&nsec3chain->db); |
| 8424 | dns_dbiterator_destroy(&nsec3chain->dbiterator); |
| 8425 | isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); |
| 8426 | nsec3chain = ISC_LIST_HEAD(cleanup); |
| 8427 | } |
| 8428 | |
| 8429 | set_resigntime(zone); |
| 8430 | |
| 8431 | failure: |
| 8432 | if (result != ISC_R_SUCCESS) { |
| 8433 | dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain: %s" , |
| 8434 | dns_result_totext(result)); |
| 8435 | } |
| 8436 | |
| 8437 | /* |
| 8438 | * On error roll back the current nsec3chain. |
| 8439 | */ |
| 8440 | if (result != ISC_R_SUCCESS && nsec3chain != NULL) { |
| 8441 | if (nsec3chain->done) { |
| 8442 | dns_db_detach(&nsec3chain->db); |
| 8443 | dns_dbiterator_destroy(&nsec3chain->dbiterator); |
| 8444 | isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); |
| 8445 | } else { |
| 8446 | result = dns_dbiterator_first(nsec3chain->dbiterator); |
| 8447 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 8448 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8449 | nsec3chain->delete_nsec = nsec3chain->save_delete_nsec; |
| 8450 | } |
| 8451 | } |
| 8452 | |
| 8453 | /* |
| 8454 | * Rollback the cleanup list. |
| 8455 | */ |
| 8456 | nsec3chain = ISC_LIST_TAIL(cleanup); |
| 8457 | while (nsec3chain != NULL) { |
| 8458 | ISC_LIST_UNLINK(cleanup, nsec3chain, link); |
| 8459 | if (nsec3chain->done) { |
| 8460 | dns_db_detach(&nsec3chain->db); |
| 8461 | dns_dbiterator_destroy(&nsec3chain->dbiterator); |
| 8462 | isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); |
| 8463 | } else { |
| 8464 | LOCK_ZONE(zone); |
| 8465 | ISC_LIST_PREPEND(zone->nsec3chain, nsec3chain, link); |
| 8466 | UNLOCK_ZONE(zone); |
| 8467 | result = dns_dbiterator_first(nsec3chain->dbiterator); |
| 8468 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 8469 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8470 | nsec3chain->delete_nsec = nsec3chain->save_delete_nsec; |
| 8471 | } |
| 8472 | nsec3chain = ISC_LIST_TAIL(cleanup); |
| 8473 | } |
| 8474 | |
| 8475 | LOCK_ZONE(zone); |
| 8476 | for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); |
| 8477 | nsec3chain != NULL; |
| 8478 | nsec3chain = ISC_LIST_NEXT(nsec3chain, link)) |
| 8479 | { |
| 8480 | dns_dbiterator_pause(nsec3chain->dbiterator); |
| 8481 | } |
| 8482 | UNLOCK_ZONE(zone); |
| 8483 | |
| 8484 | dns_diff_clear(¶m_diff); |
| 8485 | dns_diff_clear(&nsec3_diff); |
| 8486 | dns_diff_clear(&nsec_diff); |
| 8487 | dns_diff_clear(&_sig_diff); |
| 8488 | |
| 8489 | if (iterator != NULL) { |
| 8490 | dns_rdatasetiter_destroy(&iterator); |
| 8491 | } |
| 8492 | |
| 8493 | for (i = 0; i < nkeys; i++) { |
| 8494 | dst_key_free(&zone_keys[i]); |
| 8495 | } |
| 8496 | |
| 8497 | if (node != NULL) { |
| 8498 | dns_db_detachnode(db, &node); |
| 8499 | } |
| 8500 | if (version != NULL) { |
| 8501 | dns_db_closeversion(db, &version, false); |
| 8502 | dns_db_detach(&db); |
| 8503 | } else if (db != NULL) { |
| 8504 | dns_db_detach(&db); |
| 8505 | } |
| 8506 | |
| 8507 | LOCK_ZONE(zone); |
| 8508 | if (ISC_LIST_HEAD(zone->nsec3chain) != NULL) { |
| 8509 | isc_interval_t interval; |
| 8510 | if (zone->update_disabled || result != ISC_R_SUCCESS) { |
| 8511 | isc_interval_set(&interval, 60, 0); /* 1 minute */ |
| 8512 | } else { |
| 8513 | isc_interval_set(&interval, 0, 10000000); /* 10 ms */ |
| 8514 | } |
| 8515 | isc_time_nowplusinterval(&zone->nsec3chaintime, &interval); |
| 8516 | } else { |
| 8517 | isc_time_settoepoch(&zone->nsec3chaintime); |
| 8518 | } |
| 8519 | UNLOCK_ZONE(zone); |
| 8520 | |
| 8521 | INSIST(version == NULL); |
| 8522 | } |
| 8523 | |
| 8524 | /*% |
| 8525 | * Delete all RRSIG records with the given algorithm and keyid. |
| 8526 | * Remove the NSEC record and RRSIGs if nkeys is zero. |
| 8527 | * If all remaining RRsets are signed with the given algorithm |
| 8528 | * set *has_algp to true. |
| 8529 | */ |
| 8530 | static isc_result_t |
| 8531 | del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, |
| 8532 | dns_dbnode_t *node, unsigned int nkeys, dns_secalg_t algorithm, |
| 8533 | uint16_t keyid, bool *has_algp, dns_diff_t *diff) |
| 8534 | { |
| 8535 | dns_rdata_rrsig_t rrsig; |
| 8536 | dns_rdataset_t rdataset; |
| 8537 | dns_rdatasetiter_t *iterator = NULL; |
| 8538 | isc_result_t result; |
| 8539 | bool alg_missed = false; |
| 8540 | bool alg_found = false; |
| 8541 | |
| 8542 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 8543 | dns_name_format(name, namebuf, sizeof(namebuf)); |
| 8544 | |
| 8545 | result = dns_db_allrdatasets(db, node, version, 0, &iterator); |
| 8546 | if (result != ISC_R_SUCCESS) { |
| 8547 | if (result == ISC_R_NOTFOUND) |
| 8548 | result = ISC_R_SUCCESS; |
| 8549 | return (result); |
| 8550 | } |
| 8551 | |
| 8552 | dns_rdataset_init(&rdataset); |
| 8553 | for (result = dns_rdatasetiter_first(iterator); |
| 8554 | result == ISC_R_SUCCESS; |
| 8555 | result = dns_rdatasetiter_next(iterator)) { |
| 8556 | bool has_alg = false; |
| 8557 | dns_rdatasetiter_current(iterator, &rdataset); |
| 8558 | if (nkeys == 0 && rdataset.type == dns_rdatatype_nsec) { |
| 8559 | for (result = dns_rdataset_first(&rdataset); |
| 8560 | result == ISC_R_SUCCESS; |
| 8561 | result = dns_rdataset_next(&rdataset)) { |
| 8562 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 8563 | dns_rdataset_current(&rdataset, &rdata); |
| 8564 | CHECK(update_one_rr(db, version, diff, |
| 8565 | DNS_DIFFOP_DEL, name, |
| 8566 | rdataset.ttl, &rdata)); |
| 8567 | } |
| 8568 | if (result != ISC_R_NOMORE) |
| 8569 | goto failure; |
| 8570 | dns_rdataset_disassociate(&rdataset); |
| 8571 | continue; |
| 8572 | } |
| 8573 | if (rdataset.type != dns_rdatatype_rrsig) { |
| 8574 | dns_rdataset_disassociate(&rdataset); |
| 8575 | continue; |
| 8576 | } |
| 8577 | for (result = dns_rdataset_first(&rdataset); |
| 8578 | result == ISC_R_SUCCESS; |
| 8579 | result = dns_rdataset_next(&rdataset)) |
| 8580 | { |
| 8581 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 8582 | dns_rdataset_current(&rdataset, &rdata); |
| 8583 | CHECK(dns_rdata_tostruct(&rdata, &rrsig, NULL)); |
| 8584 | if (nkeys != 0 && |
| 8585 | (rrsig.algorithm != algorithm || |
| 8586 | rrsig.keyid != keyid)) |
| 8587 | { |
| 8588 | if (rrsig.algorithm == algorithm) { |
| 8589 | has_alg = true; |
| 8590 | } |
| 8591 | continue; |
| 8592 | } |
| 8593 | CHECK(update_one_rr(db, version, diff, |
| 8594 | DNS_DIFFOP_DELRESIGN, name, |
| 8595 | rdataset.ttl, &rdata)); |
| 8596 | } |
| 8597 | dns_rdataset_disassociate(&rdataset); |
| 8598 | if (result != ISC_R_NOMORE) |
| 8599 | break; |
| 8600 | |
| 8601 | /* |
| 8602 | * After deleting, if there's still a signature for |
| 8603 | * 'algorithm', set alg_found; if not, set alg_missed. |
| 8604 | */ |
| 8605 | if (has_alg) { |
| 8606 | alg_found = true; |
| 8607 | } else { |
| 8608 | alg_missed = true; |
| 8609 | } |
| 8610 | } |
| 8611 | if (result == ISC_R_NOMORE) |
| 8612 | result = ISC_R_SUCCESS; |
| 8613 | |
| 8614 | /* |
| 8615 | * Set `has_algp` if the algorithm was found in every RRset: |
| 8616 | * i.e., found in at least one, and not missing from any. |
| 8617 | */ |
| 8618 | *has_algp = (alg_found && !alg_missed); |
| 8619 | failure: |
| 8620 | if (dns_rdataset_isassociated(&rdataset)) |
| 8621 | dns_rdataset_disassociate(&rdataset); |
| 8622 | dns_rdatasetiter_destroy(&iterator); |
| 8623 | return (result); |
| 8624 | } |
| 8625 | |
| 8626 | /* |
| 8627 | * Incrementally sign the zone using the keys requested. |
| 8628 | * Builds the NSEC chain if required. |
| 8629 | */ |
| 8630 | static void |
| 8631 | zone_sign(dns_zone_t *zone) { |
| 8632 | const char *me = "zone_sign" ; |
| 8633 | dns_db_t *db = NULL; |
| 8634 | dns_dbnode_t *node = NULL; |
| 8635 | dns_dbversion_t *version = NULL; |
| 8636 | dns_diff_t _sig_diff; |
| 8637 | dns_diff_t post_diff; |
| 8638 | dns__zonediff_t zonediff; |
| 8639 | dns_fixedname_t fixed; |
| 8640 | dns_fixedname_t nextfixed; |
| 8641 | dns_name_t *name, *nextname; |
| 8642 | dns_rdataset_t rdataset; |
| 8643 | dns_signing_t *signing, *nextsigning; |
| 8644 | dns_signinglist_t cleanup; |
| 8645 | dst_key_t *zone_keys[DNS_MAXZONEKEYS]; |
| 8646 | int32_t signatures; |
| 8647 | bool check_ksk, keyset_kskonly, is_ksk; |
| 8648 | bool with_ksk, with_zsk; |
| 8649 | bool commit = false; |
| 8650 | bool is_bottom_of_zone; |
| 8651 | bool build_nsec = false; |
| 8652 | bool build_nsec3 = false; |
| 8653 | bool first; |
| 8654 | isc_result_t result; |
| 8655 | isc_stdtime_t now, inception, soaexpire, expire; |
| 8656 | uint32_t jitter, sigvalidityinterval, expiryinterval; |
| 8657 | unsigned int i, j; |
| 8658 | unsigned int nkeys = 0; |
| 8659 | uint32_t nodes; |
| 8660 | |
| 8661 | ENTER; |
| 8662 | |
| 8663 | dns_rdataset_init(&rdataset); |
| 8664 | name = dns_fixedname_initname(&fixed); |
| 8665 | nextname = dns_fixedname_initname(&nextfixed); |
| 8666 | dns_diff_init(zone->mctx, &_sig_diff); |
| 8667 | dns_diff_init(zone->mctx, &post_diff); |
| 8668 | zonediff_init(&zonediff, &_sig_diff); |
| 8669 | ISC_LIST_INIT(cleanup); |
| 8670 | |
| 8671 | /* |
| 8672 | * Updates are disabled. Pause for 1 minute. |
| 8673 | */ |
| 8674 | if (zone->update_disabled) { |
| 8675 | result = ISC_R_FAILURE; |
| 8676 | goto cleanup; |
| 8677 | } |
| 8678 | |
| 8679 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 8680 | if (zone->db != NULL) { |
| 8681 | dns_db_attach(zone->db, &db); |
| 8682 | } |
| 8683 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 8684 | if (db == NULL) { |
| 8685 | result = ISC_R_FAILURE; |
| 8686 | goto cleanup; |
| 8687 | } |
| 8688 | |
| 8689 | result = dns_db_newversion(db, &version); |
| 8690 | if (result != ISC_R_SUCCESS) { |
| 8691 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8692 | "zone_sign:dns_db_newversion -> %s" , |
| 8693 | dns_result_totext(result)); |
| 8694 | goto cleanup; |
| 8695 | } |
| 8696 | |
| 8697 | isc_stdtime_get(&now); |
| 8698 | |
| 8699 | result = dns__zone_findkeys(zone, db, version, now, zone->mctx, |
| 8700 | DNS_MAXZONEKEYS, zone_keys, &nkeys); |
| 8701 | if (result != ISC_R_SUCCESS) { |
| 8702 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8703 | "zone_sign:dns__zone_findkeys -> %s" , |
| 8704 | dns_result_totext(result)); |
| 8705 | goto cleanup; |
| 8706 | } |
| 8707 | |
| 8708 | sigvalidityinterval = dns_zone_getsigvalidityinterval(zone); |
| 8709 | inception = now - 3600; /* Allow for clock skew. */ |
| 8710 | soaexpire = now + sigvalidityinterval; |
| 8711 | expiryinterval = dns_zone_getsigresigninginterval(zone); |
| 8712 | if (expiryinterval > sigvalidityinterval) { |
| 8713 | expiryinterval = sigvalidityinterval; |
| 8714 | } else { |
| 8715 | expiryinterval = sigvalidityinterval - expiryinterval; |
| 8716 | } |
| 8717 | |
| 8718 | /* |
| 8719 | * Spread out signatures over time if they happen to be |
| 8720 | * clumped. We don't do this for each add_sigs() call as |
| 8721 | * we still want some clustering to occur. |
| 8722 | */ |
| 8723 | if (sigvalidityinterval >= 3600U) { |
| 8724 | if (sigvalidityinterval > 7200U) { |
| 8725 | jitter = isc_random_uniform(expiryinterval); |
| 8726 | } else { |
| 8727 | jitter = isc_random_uniform(1200); |
| 8728 | } |
| 8729 | expire = soaexpire - jitter - 1; |
| 8730 | } else { |
| 8731 | expire = soaexpire - 1; |
| 8732 | } |
| 8733 | |
| 8734 | /* |
| 8735 | * We keep pulling nodes off each iterator in turn until |
| 8736 | * we have no more nodes to pull off or we reach the limits |
| 8737 | * for this quantum. |
| 8738 | */ |
| 8739 | nodes = zone->nodes; |
| 8740 | signatures = zone->signatures; |
| 8741 | signing = ISC_LIST_HEAD(zone->signing); |
| 8742 | first = true; |
| 8743 | |
| 8744 | check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); |
| 8745 | keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); |
| 8746 | |
| 8747 | /* Determine which type of chain to build */ |
| 8748 | CHECK(dns_private_chains(db, version, zone->privatetype, |
| 8749 | &build_nsec, &build_nsec3)); |
| 8750 | |
| 8751 | /* If neither chain is found, default to NSEC */ |
| 8752 | if (!build_nsec && !build_nsec3) { |
| 8753 | build_nsec = true; |
| 8754 | } |
| 8755 | |
| 8756 | while (signing != NULL && nodes-- > 0 && signatures > 0) { |
| 8757 | bool has_alg = false; |
| 8758 | nextsigning = ISC_LIST_NEXT(signing, link); |
| 8759 | |
| 8760 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 8761 | if (signing->done || signing->db != zone->db) { |
| 8762 | /* |
| 8763 | * The zone has been reloaded. We will have |
| 8764 | * created new signings as part of the reload |
| 8765 | * process so we can destroy this one. |
| 8766 | */ |
| 8767 | ISC_LIST_UNLINK(zone->signing, signing, link); |
| 8768 | ISC_LIST_APPEND(cleanup, signing, link); |
| 8769 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 8770 | goto next_signing; |
| 8771 | } |
| 8772 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 8773 | |
| 8774 | if (signing->db != db) { |
| 8775 | goto next_signing; |
| 8776 | } |
| 8777 | |
| 8778 | is_bottom_of_zone = false; |
| 8779 | |
| 8780 | if (first && signing->deleteit) { |
| 8781 | /* |
| 8782 | * Remove the key we are deleting from consideration. |
| 8783 | */ |
| 8784 | for (i = 0, j = 0; i < nkeys; i++) { |
| 8785 | /* |
| 8786 | * Find the key we want to remove. |
| 8787 | */ |
| 8788 | if (ALG(zone_keys[i]) == signing->algorithm && |
| 8789 | dst_key_id(zone_keys[i]) == signing->keyid) |
| 8790 | { |
| 8791 | if (KSK(zone_keys[i])) |
| 8792 | dst_key_free(&zone_keys[i]); |
| 8793 | continue; |
| 8794 | } |
| 8795 | zone_keys[j] = zone_keys[i]; |
| 8796 | j++; |
| 8797 | } |
| 8798 | for (i = j; i < nkeys; i++) { |
| 8799 | zone_keys[i] = NULL; |
| 8800 | } |
| 8801 | nkeys = j; |
| 8802 | } |
| 8803 | |
| 8804 | dns_dbiterator_current(signing->dbiterator, &node, name); |
| 8805 | |
| 8806 | if (signing->deleteit) { |
| 8807 | dns_dbiterator_pause(signing->dbiterator); |
| 8808 | CHECK(del_sig(db, version, name, node, nkeys, |
| 8809 | signing->algorithm, signing->keyid, |
| 8810 | &has_alg, zonediff.diff)); |
| 8811 | } |
| 8812 | |
| 8813 | /* |
| 8814 | * On the first pass we need to check if the current node |
| 8815 | * has not been obscured. |
| 8816 | */ |
| 8817 | if (first) { |
| 8818 | dns_fixedname_t ffound; |
| 8819 | dns_name_t *found; |
| 8820 | found = dns_fixedname_initname(&ffound); |
| 8821 | result = dns_db_find(db, name, version, |
| 8822 | dns_rdatatype_soa, |
| 8823 | DNS_DBFIND_NOWILD, 0, NULL, found, |
| 8824 | NULL, NULL); |
| 8825 | if ((result == DNS_R_DELEGATION || |
| 8826 | result == DNS_R_DNAME) && |
| 8827 | !dns_name_equal(name, found)) |
| 8828 | { |
| 8829 | /* |
| 8830 | * Remember the obscuring name so that |
| 8831 | * we skip all obscured names. |
| 8832 | */ |
| 8833 | dns_name_copy(found, name, NULL); |
| 8834 | is_bottom_of_zone = true; |
| 8835 | goto next_node; |
| 8836 | } |
| 8837 | } |
| 8838 | |
| 8839 | /* |
| 8840 | * Process one node. |
| 8841 | */ |
| 8842 | with_ksk = false; |
| 8843 | with_zsk = false; |
| 8844 | dns_dbiterator_pause(signing->dbiterator); |
| 8845 | |
| 8846 | CHECK(check_if_bottom_of_zone(db, node, version, |
| 8847 | &is_bottom_of_zone)); |
| 8848 | |
| 8849 | for (i = 0; !has_alg && i < nkeys; i++) { |
| 8850 | bool both = false; |
| 8851 | |
| 8852 | /* |
| 8853 | * Find the keys we want to sign with. |
| 8854 | */ |
| 8855 | if (!dst_key_isprivate(zone_keys[i])) { |
| 8856 | continue; |
| 8857 | } |
| 8858 | /* |
| 8859 | * Should be redundant. |
| 8860 | */ |
| 8861 | if (dst_key_inactive(zone_keys[i])) { |
| 8862 | continue; |
| 8863 | } |
| 8864 | |
| 8865 | /* |
| 8866 | * When adding look for the specific key. |
| 8867 | */ |
| 8868 | if (!signing->deleteit && |
| 8869 | (dst_key_alg(zone_keys[i]) != signing->algorithm || |
| 8870 | dst_key_id(zone_keys[i]) != signing->keyid)) |
| 8871 | { |
| 8872 | continue; |
| 8873 | } |
| 8874 | |
| 8875 | /* |
| 8876 | * When deleting make sure we are properly signed |
| 8877 | * with the algorithm that was being removed. |
| 8878 | */ |
| 8879 | if (signing->deleteit && |
| 8880 | ALG(zone_keys[i]) != signing->algorithm) |
| 8881 | { |
| 8882 | continue; |
| 8883 | } |
| 8884 | |
| 8885 | /* |
| 8886 | * Do we do KSK processing? |
| 8887 | */ |
| 8888 | if (check_ksk && !REVOKE(zone_keys[i])) { |
| 8889 | bool have_ksk, have_nonksk; |
| 8890 | if (KSK(zone_keys[i])) { |
| 8891 | have_ksk = true; |
| 8892 | have_nonksk = false; |
| 8893 | } else { |
| 8894 | have_ksk = false; |
| 8895 | have_nonksk = true; |
| 8896 | } |
| 8897 | for (j = 0; j < nkeys; j++) { |
| 8898 | if (j == i || |
| 8899 | (ALG(zone_keys[i]) != |
| 8900 | ALG(zone_keys[j]))) |
| 8901 | { |
| 8902 | continue; |
| 8903 | } |
| 8904 | if (!dst_key_isprivate(zone_keys[j])) { |
| 8905 | continue; |
| 8906 | } |
| 8907 | /* |
| 8908 | * Should be redundant. |
| 8909 | */ |
| 8910 | if (dst_key_inactive(zone_keys[j])) { |
| 8911 | continue; |
| 8912 | } |
| 8913 | if (REVOKE(zone_keys[j])) { |
| 8914 | continue; |
| 8915 | } |
| 8916 | if (KSK(zone_keys[j])) { |
| 8917 | have_ksk = true; |
| 8918 | } else { |
| 8919 | have_nonksk = true; |
| 8920 | } |
| 8921 | both = have_ksk && have_nonksk; |
| 8922 | if (both) { |
| 8923 | break; |
| 8924 | } |
| 8925 | } |
| 8926 | } |
| 8927 | if (both || REVOKE(zone_keys[i])) { |
| 8928 | is_ksk = KSK(zone_keys[i]); |
| 8929 | } else { |
| 8930 | is_ksk = false; |
| 8931 | } |
| 8932 | |
| 8933 | /* |
| 8934 | * If deleting signatures, we need to ensure that |
| 8935 | * the RRset is still signed at least once by a |
| 8936 | * KSK and a ZSK. |
| 8937 | */ |
| 8938 | if (signing->deleteit && !is_ksk && with_zsk) { |
| 8939 | continue; |
| 8940 | } |
| 8941 | |
| 8942 | if (signing->deleteit && is_ksk && with_ksk) { |
| 8943 | continue; |
| 8944 | } |
| 8945 | |
| 8946 | CHECK(sign_a_node(db, name, node, version, build_nsec3, |
| 8947 | build_nsec, zone_keys[i], inception, |
| 8948 | expire, zone->minimum, is_ksk, |
| 8949 | (both && keyset_kskonly), |
| 8950 | is_bottom_of_zone, zonediff.diff, |
| 8951 | &signatures, zone->mctx)); |
| 8952 | /* |
| 8953 | * If we are adding we are done. Look for other keys |
| 8954 | * of the same algorithm if deleting. |
| 8955 | */ |
| 8956 | if (!signing->deleteit) { |
| 8957 | break; |
| 8958 | } |
| 8959 | if (!is_ksk) { |
| 8960 | with_zsk = true; |
| 8961 | } |
| 8962 | if (KSK(zone_keys[i])) { |
| 8963 | with_ksk = true; |
| 8964 | } |
| 8965 | } |
| 8966 | |
| 8967 | /* |
| 8968 | * Go onto next node. |
| 8969 | */ |
| 8970 | next_node: |
| 8971 | first = false; |
| 8972 | dns_db_detachnode(db, &node); |
| 8973 | do { |
| 8974 | result = dns_dbiterator_next(signing->dbiterator); |
| 8975 | if (result == ISC_R_NOMORE) { |
| 8976 | ISC_LIST_UNLINK(zone->signing, signing, link); |
| 8977 | ISC_LIST_APPEND(cleanup, signing, link); |
| 8978 | dns_dbiterator_pause(signing->dbiterator); |
| 8979 | if (nkeys != 0 && build_nsec) { |
| 8980 | /* |
| 8981 | * We have finished regenerating the |
| 8982 | * zone with a zone signing key. |
| 8983 | * The NSEC chain is now complete and |
| 8984 | * there is a full set of signatures |
| 8985 | * for the zone. We can now clear the |
| 8986 | * OPT bit from the NSEC record. |
| 8987 | */ |
| 8988 | result = updatesecure(db, version, |
| 8989 | &zone->origin, |
| 8990 | zone->minimum, |
| 8991 | false, |
| 8992 | &post_diff); |
| 8993 | if (result != ISC_R_SUCCESS) { |
| 8994 | dnssec_log(zone, ISC_LOG_ERROR, |
| 8995 | "updatesecure -> %s" , |
| 8996 | dns_result_totext(result)); |
| 8997 | goto cleanup; |
| 8998 | } |
| 8999 | } |
| 9000 | result = updatesignwithkey(zone, signing, |
| 9001 | version, |
| 9002 | build_nsec3, |
| 9003 | zone->minimum, |
| 9004 | &post_diff); |
| 9005 | if (result != ISC_R_SUCCESS) { |
| 9006 | dnssec_log(zone, ISC_LOG_ERROR, |
| 9007 | "updatesignwithkey -> %s" , |
| 9008 | dns_result_totext(result)); |
| 9009 | goto cleanup; |
| 9010 | } |
| 9011 | build_nsec = false; |
| 9012 | goto next_signing; |
| 9013 | } else if (result != ISC_R_SUCCESS) { |
| 9014 | dnssec_log(zone, ISC_LOG_ERROR, |
| 9015 | "zone_sign:" |
| 9016 | "dns_dbiterator_next -> %s" , |
| 9017 | dns_result_totext(result)); |
| 9018 | goto cleanup; |
| 9019 | } else if (is_bottom_of_zone) { |
| 9020 | dns_dbiterator_current(signing->dbiterator, |
| 9021 | &node, nextname); |
| 9022 | dns_db_detachnode(db, &node); |
| 9023 | if (!dns_name_issubdomain(nextname, name)) { |
| 9024 | break; |
| 9025 | } |
| 9026 | } else { |
| 9027 | break; |
| 9028 | } |
| 9029 | } while (1); |
| 9030 | continue; |
| 9031 | |
| 9032 | next_signing: |
| 9033 | dns_dbiterator_pause(signing->dbiterator); |
| 9034 | signing = nextsigning; |
| 9035 | first = true; |
| 9036 | } |
| 9037 | |
| 9038 | if (ISC_LIST_HEAD(post_diff.tuples) != NULL) { |
| 9039 | result = dns__zone_updatesigs(&post_diff, db, version, |
| 9040 | zone_keys, nkeys, zone, |
| 9041 | inception, expire, 0, now, |
| 9042 | check_ksk, keyset_kskonly, |
| 9043 | &zonediff); |
| 9044 | if (result != ISC_R_SUCCESS) { |
| 9045 | dnssec_log(zone, ISC_LOG_ERROR, |
| 9046 | "zone_sign:dns__zone_updatesigs -> %s" , |
| 9047 | dns_result_totext(result)); |
| 9048 | goto cleanup; |
| 9049 | } |
| 9050 | } |
| 9051 | |
| 9052 | /* |
| 9053 | * Have we changed anything? |
| 9054 | */ |
| 9055 | if (ISC_LIST_EMPTY(zonediff.diff->tuples)) { |
| 9056 | if (zonediff.offline) { |
| 9057 | commit = true; |
| 9058 | } |
| 9059 | result = ISC_R_SUCCESS; |
| 9060 | goto pauseall; |
| 9061 | } |
| 9062 | |
| 9063 | commit = true; |
| 9064 | |
| 9065 | result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, |
| 9066 | &zonediff, zone_keys, nkeys, now, false); |
| 9067 | if (result != ISC_R_SUCCESS) { |
| 9068 | dnssec_log(zone, ISC_LOG_ERROR, "zone_sign:del_sigs -> %s" , |
| 9069 | dns_result_totext(result)); |
| 9070 | goto cleanup; |
| 9071 | } |
| 9072 | |
| 9073 | result = update_soa_serial(db, version, zonediff.diff, zone->mctx, |
| 9074 | zone->updatemethod); |
| 9075 | if (result != ISC_R_SUCCESS) { |
| 9076 | dnssec_log(zone, ISC_LOG_ERROR, |
| 9077 | "zone_sign:update_soa_serial -> %s" , |
| 9078 | dns_result_totext(result)); |
| 9079 | goto cleanup; |
| 9080 | } |
| 9081 | |
| 9082 | /* |
| 9083 | * Generate maximum life time signatures so that the above loop |
| 9084 | * termination is sensible. |
| 9085 | */ |
| 9086 | result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, |
| 9087 | zonediff.diff, zone_keys, nkeys, zone->mctx, |
| 9088 | inception, soaexpire, check_ksk, keyset_kskonly); |
| 9089 | if (result != ISC_R_SUCCESS) { |
| 9090 | dnssec_log(zone, ISC_LOG_ERROR, "zone_sign:add_sigs -> %s" , |
| 9091 | dns_result_totext(result)); |
| 9092 | goto cleanup; |
| 9093 | } |
| 9094 | |
| 9095 | /* |
| 9096 | * Write changes to journal file. |
| 9097 | */ |
| 9098 | CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_sign" )); |
| 9099 | |
| 9100 | pauseall: |
| 9101 | /* |
| 9102 | * Pause all iterators so that dns_db_closeversion() can succeed. |
| 9103 | */ |
| 9104 | for (signing = ISC_LIST_HEAD(zone->signing); |
| 9105 | signing != NULL; |
| 9106 | signing = ISC_LIST_NEXT(signing, link)) |
| 9107 | { |
| 9108 | dns_dbiterator_pause(signing->dbiterator); |
| 9109 | } |
| 9110 | |
| 9111 | for (signing = ISC_LIST_HEAD(cleanup); |
| 9112 | signing != NULL; |
| 9113 | signing = ISC_LIST_NEXT(signing, link)) |
| 9114 | { |
| 9115 | dns_dbiterator_pause(signing->dbiterator); |
| 9116 | } |
| 9117 | |
| 9118 | /* |
| 9119 | * Everything has succeeded. Commit the changes. |
| 9120 | */ |
| 9121 | dns_db_closeversion(db, &version, commit); |
| 9122 | |
| 9123 | /* |
| 9124 | * Everything succeeded so we can clean these up now. |
| 9125 | */ |
| 9126 | signing = ISC_LIST_HEAD(cleanup); |
| 9127 | while (signing != NULL) { |
| 9128 | ISC_LIST_UNLINK(cleanup, signing, link); |
| 9129 | dns_db_detach(&signing->db); |
| 9130 | dns_dbiterator_destroy(&signing->dbiterator); |
| 9131 | isc_mem_put(zone->mctx, signing, sizeof *signing); |
| 9132 | signing = ISC_LIST_HEAD(cleanup); |
| 9133 | } |
| 9134 | |
| 9135 | set_resigntime(zone); |
| 9136 | |
| 9137 | if (commit) { |
| 9138 | LOCK_ZONE(zone); |
| 9139 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 9140 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 9141 | UNLOCK_ZONE(zone); |
| 9142 | } |
| 9143 | |
| 9144 | failure: |
| 9145 | if (result != ISC_R_SUCCESS) { |
| 9146 | dnssec_log(zone, ISC_LOG_ERROR, "zone_sign: failed: %s" , |
| 9147 | dns_result_totext(result)); |
| 9148 | } |
| 9149 | |
| 9150 | cleanup: |
| 9151 | /* |
| 9152 | * Pause all dbiterators. |
| 9153 | */ |
| 9154 | for (signing = ISC_LIST_HEAD(zone->signing); |
| 9155 | signing != NULL; |
| 9156 | signing = ISC_LIST_NEXT(signing, link)) |
| 9157 | { |
| 9158 | dns_dbiterator_pause(signing->dbiterator); |
| 9159 | } |
| 9160 | |
| 9161 | /* |
| 9162 | * Rollback the cleanup list. |
| 9163 | */ |
| 9164 | signing = ISC_LIST_HEAD(cleanup); |
| 9165 | while (signing != NULL) { |
| 9166 | ISC_LIST_UNLINK(cleanup, signing, link); |
| 9167 | ISC_LIST_PREPEND(zone->signing, signing, link); |
| 9168 | dns_dbiterator_first(signing->dbiterator); |
| 9169 | dns_dbiterator_pause(signing->dbiterator); |
| 9170 | signing = ISC_LIST_HEAD(cleanup); |
| 9171 | } |
| 9172 | |
| 9173 | dns_diff_clear(&_sig_diff); |
| 9174 | |
| 9175 | for (i = 0; i < nkeys; i++) { |
| 9176 | dst_key_free(&zone_keys[i]); |
| 9177 | } |
| 9178 | |
| 9179 | if (node != NULL) { |
| 9180 | dns_db_detachnode(db, &node); |
| 9181 | } |
| 9182 | |
| 9183 | if (version != NULL) { |
| 9184 | dns_db_closeversion(db, &version, false); |
| 9185 | dns_db_detach(&db); |
| 9186 | } else if (db != NULL) { |
| 9187 | dns_db_detach(&db); |
| 9188 | } |
| 9189 | |
| 9190 | if (ISC_LIST_HEAD(zone->signing) != NULL) { |
| 9191 | isc_interval_t interval; |
| 9192 | if (zone->update_disabled || result != ISC_R_SUCCESS) { |
| 9193 | isc_interval_set(&interval, 60, 0); /* 1 minute */ |
| 9194 | } else { |
| 9195 | isc_interval_set(&interval, 0, 10000000); /* 10 ms */ |
| 9196 | } |
| 9197 | isc_time_nowplusinterval(&zone->signingtime, &interval); |
| 9198 | } else { |
| 9199 | isc_time_settoepoch(&zone->signingtime); |
| 9200 | } |
| 9201 | |
| 9202 | INSIST(version == NULL); |
| 9203 | } |
| 9204 | |
| 9205 | static isc_result_t |
| 9206 | normalize_key(dns_rdata_t *rr, dns_rdata_t *target, |
| 9207 | unsigned char *data, int size) |
| 9208 | { |
| 9209 | dns_rdata_dnskey_t dnskey; |
| 9210 | dns_rdata_keydata_t keydata; |
| 9211 | isc_buffer_t buf; |
| 9212 | isc_result_t result; |
| 9213 | |
| 9214 | dns_rdata_reset(target); |
| 9215 | isc_buffer_init(&buf, data, size); |
| 9216 | |
| 9217 | switch (rr->type) { |
| 9218 | case dns_rdatatype_dnskey: |
| 9219 | result = dns_rdata_tostruct(rr, &dnskey, NULL); |
| 9220 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9221 | dnskey.flags &= ~DNS_KEYFLAG_REVOKE; |
| 9222 | dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey, |
| 9223 | &dnskey, &buf); |
| 9224 | break; |
| 9225 | case dns_rdatatype_keydata: |
| 9226 | result = dns_rdata_tostruct(rr, &keydata, NULL); |
| 9227 | if (result == ISC_R_UNEXPECTEDEND) |
| 9228 | return (result); |
| 9229 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9230 | dns_keydata_todnskey(&keydata, &dnskey, NULL); |
| 9231 | dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey, |
| 9232 | &dnskey, &buf); |
| 9233 | break; |
| 9234 | default: |
| 9235 | INSIST(0); |
| 9236 | ISC_UNREACHABLE(); |
| 9237 | } |
| 9238 | return (ISC_R_SUCCESS); |
| 9239 | } |
| 9240 | |
| 9241 | /* |
| 9242 | * 'rdset' contains either a DNSKEY rdataset from the zone apex, or |
| 9243 | * a KEYDATA rdataset from the key zone. |
| 9244 | * |
| 9245 | * 'rr' contains either a DNSKEY record, or a KEYDATA record |
| 9246 | * |
| 9247 | * After normalizing keys to the same format (DNSKEY, with revoke bit |
| 9248 | * cleared), return true if a key that matches 'rr' is found in |
| 9249 | * 'rdset', or false if not. |
| 9250 | */ |
| 9251 | |
| 9252 | static bool |
| 9253 | matchkey(dns_rdataset_t *rdset, dns_rdata_t *rr) { |
| 9254 | unsigned char data1[4096], data2[4096]; |
| 9255 | dns_rdata_t rdata, rdata1, rdata2; |
| 9256 | isc_result_t result; |
| 9257 | |
| 9258 | dns_rdata_init(&rdata); |
| 9259 | dns_rdata_init(&rdata1); |
| 9260 | dns_rdata_init(&rdata2); |
| 9261 | |
| 9262 | result = normalize_key(rr, &rdata1, data1, sizeof(data1)); |
| 9263 | if (result != ISC_R_SUCCESS) |
| 9264 | return (false); |
| 9265 | |
| 9266 | for (result = dns_rdataset_first(rdset); |
| 9267 | result == ISC_R_SUCCESS; |
| 9268 | result = dns_rdataset_next(rdset)) { |
| 9269 | dns_rdata_reset(&rdata); |
| 9270 | dns_rdataset_current(rdset, &rdata); |
| 9271 | result = normalize_key(&rdata, &rdata2, data2, sizeof(data2)); |
| 9272 | if (result != ISC_R_SUCCESS) |
| 9273 | continue; |
| 9274 | if (dns_rdata_compare(&rdata1, &rdata2) == 0) |
| 9275 | return (true); |
| 9276 | } |
| 9277 | |
| 9278 | return (false); |
| 9279 | } |
| 9280 | |
| 9281 | /* |
| 9282 | * Calculate the refresh interval for a keydata zone, per |
| 9283 | * RFC5011: MAX(1 hr, |
| 9284 | * MIN(15 days, |
| 9285 | * 1/2 * OrigTTL, |
| 9286 | * 1/2 * RRSigExpirationInterval)) |
| 9287 | * or for retries: MAX(1 hr, |
| 9288 | * MIN(1 day, |
| 9289 | * 1/10 * OrigTTL, |
| 9290 | * 1/10 * RRSigExpirationInterval)) |
| 9291 | */ |
| 9292 | static inline isc_stdtime_t |
| 9293 | refresh_time(dns_keyfetch_t *kfetch, bool retry) { |
| 9294 | isc_result_t result; |
| 9295 | uint32_t t; |
| 9296 | dns_rdataset_t *rdset; |
| 9297 | dns_rdata_t sigrr = DNS_RDATA_INIT; |
| 9298 | dns_rdata_sig_t sig; |
| 9299 | isc_stdtime_t now; |
| 9300 | |
| 9301 | isc_stdtime_get(&now); |
| 9302 | |
| 9303 | if (dns_rdataset_isassociated(&kfetch->dnskeysigset)) |
| 9304 | rdset = &kfetch->dnskeysigset; |
| 9305 | else |
| 9306 | return (now + dns_zone_mkey_hour); |
| 9307 | |
| 9308 | result = dns_rdataset_first(rdset); |
| 9309 | if (result != ISC_R_SUCCESS) |
| 9310 | return (now + dns_zone_mkey_hour); |
| 9311 | |
| 9312 | dns_rdataset_current(rdset, &sigrr); |
| 9313 | result = dns_rdata_tostruct(&sigrr, &sig, NULL); |
| 9314 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9315 | |
| 9316 | if (!retry) { |
| 9317 | t = sig.originalttl / 2; |
| 9318 | |
| 9319 | if (isc_serial_gt(sig.timeexpire, now)) { |
| 9320 | uint32_t exp = (sig.timeexpire - now) / 2; |
| 9321 | if (t > exp) |
| 9322 | t = exp; |
| 9323 | } |
| 9324 | |
| 9325 | if (t > (15 * dns_zone_mkey_day)) |
| 9326 | t = (15 * dns_zone_mkey_day); |
| 9327 | |
| 9328 | if (t < dns_zone_mkey_hour) |
| 9329 | t = dns_zone_mkey_hour; |
| 9330 | } else { |
| 9331 | t = sig.originalttl / 10; |
| 9332 | |
| 9333 | if (isc_serial_gt(sig.timeexpire, now)) { |
| 9334 | uint32_t exp = (sig.timeexpire - now) / 10; |
| 9335 | if (t > exp) |
| 9336 | t = exp; |
| 9337 | } |
| 9338 | |
| 9339 | if (t > dns_zone_mkey_day) |
| 9340 | t = dns_zone_mkey_day; |
| 9341 | |
| 9342 | if (t < dns_zone_mkey_hour) |
| 9343 | t = dns_zone_mkey_hour; |
| 9344 | } |
| 9345 | |
| 9346 | return (now + t); |
| 9347 | } |
| 9348 | |
| 9349 | /* |
| 9350 | * This routine is called when no changes are needed in a KEYDATA |
| 9351 | * record except to simply update the refresh timer. Caller should |
| 9352 | * hold zone lock. |
| 9353 | */ |
| 9354 | static isc_result_t |
| 9355 | minimal_update(dns_keyfetch_t *kfetch, dns_dbversion_t *ver, dns_diff_t *diff) |
| 9356 | { |
| 9357 | isc_result_t result; |
| 9358 | isc_buffer_t keyb; |
| 9359 | unsigned char key_buf[4096]; |
| 9360 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 9361 | dns_rdata_keydata_t keydata; |
| 9362 | dns_name_t *name; |
| 9363 | dns_zone_t *zone = kfetch->zone; |
| 9364 | isc_stdtime_t now; |
| 9365 | |
| 9366 | name = dns_fixedname_name(&kfetch->name); |
| 9367 | isc_stdtime_get(&now); |
| 9368 | |
| 9369 | for (result = dns_rdataset_first(&kfetch->keydataset); |
| 9370 | result == ISC_R_SUCCESS; |
| 9371 | result = dns_rdataset_next(&kfetch->keydataset)) { |
| 9372 | dns_rdata_reset(&rdata); |
| 9373 | dns_rdataset_current(&kfetch->keydataset, &rdata); |
| 9374 | |
| 9375 | /* Delete old version */ |
| 9376 | CHECK(update_one_rr(kfetch->db, ver, diff, DNS_DIFFOP_DEL, |
| 9377 | name, 0, &rdata)); |
| 9378 | |
| 9379 | /* Update refresh timer */ |
| 9380 | result = dns_rdata_tostruct(&rdata, &keydata, NULL); |
| 9381 | if (result == ISC_R_UNEXPECTEDEND) |
| 9382 | continue; |
| 9383 | if (result != ISC_R_SUCCESS) |
| 9384 | goto failure; |
| 9385 | keydata.refresh = refresh_time(kfetch, true); |
| 9386 | set_refreshkeytimer(zone, &keydata, now, false); |
| 9387 | |
| 9388 | dns_rdata_reset(&rdata); |
| 9389 | isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); |
| 9390 | CHECK(dns_rdata_fromstruct(&rdata, |
| 9391 | zone->rdclass, dns_rdatatype_keydata, |
| 9392 | &keydata, &keyb)); |
| 9393 | |
| 9394 | /* Insert updated version */ |
| 9395 | CHECK(update_one_rr(kfetch->db, ver, diff, DNS_DIFFOP_ADD, |
| 9396 | name, 0, &rdata)); |
| 9397 | } |
| 9398 | result = ISC_R_SUCCESS; |
| 9399 | failure: |
| 9400 | return (result); |
| 9401 | } |
| 9402 | |
| 9403 | /* |
| 9404 | * Verify that DNSKEY set is signed by the key specified in 'keydata'. |
| 9405 | */ |
| 9406 | static bool |
| 9407 | revocable(dns_keyfetch_t *kfetch, dns_rdata_keydata_t *keydata) { |
| 9408 | isc_result_t result; |
| 9409 | dns_name_t *keyname; |
| 9410 | isc_mem_t *mctx; |
| 9411 | dns_rdata_t sigrr = DNS_RDATA_INIT; |
| 9412 | dns_rdata_t rr = DNS_RDATA_INIT; |
| 9413 | dns_rdata_rrsig_t sig; |
| 9414 | dns_rdata_dnskey_t dnskey; |
| 9415 | dst_key_t *dstkey = NULL; |
| 9416 | unsigned char key_buf[4096]; |
| 9417 | isc_buffer_t keyb; |
| 9418 | bool answer = false; |
| 9419 | |
| 9420 | REQUIRE(kfetch != NULL && keydata != NULL); |
| 9421 | REQUIRE(dns_rdataset_isassociated(&kfetch->dnskeysigset)); |
| 9422 | |
| 9423 | keyname = dns_fixedname_name(&kfetch->name); |
| 9424 | mctx = kfetch->zone->view->mctx; |
| 9425 | |
| 9426 | /* Generate a key from keydata */ |
| 9427 | isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); |
| 9428 | dns_keydata_todnskey(keydata, &dnskey, NULL); |
| 9429 | dns_rdata_fromstruct(&rr, keydata->common.rdclass, |
| 9430 | dns_rdatatype_dnskey, &dnskey, &keyb); |
| 9431 | result = dns_dnssec_keyfromrdata(keyname, &rr, mctx, &dstkey); |
| 9432 | if (result != ISC_R_SUCCESS) { |
| 9433 | return (false); |
| 9434 | } |
| 9435 | |
| 9436 | /* See if that key generated any of the signatures */ |
| 9437 | for (result = dns_rdataset_first(&kfetch->dnskeysigset); |
| 9438 | result == ISC_R_SUCCESS; |
| 9439 | result = dns_rdataset_next(&kfetch->dnskeysigset)) |
| 9440 | { |
| 9441 | dns_fixedname_t fixed; |
| 9442 | dns_fixedname_init(&fixed); |
| 9443 | |
| 9444 | dns_rdata_reset(&sigrr); |
| 9445 | dns_rdataset_current(&kfetch->dnskeysigset, &sigrr); |
| 9446 | result = dns_rdata_tostruct(&sigrr, &sig, NULL); |
| 9447 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9448 | |
| 9449 | if (dst_key_alg(dstkey) == sig.algorithm && |
| 9450 | dst_key_rid(dstkey) == sig.keyid) |
| 9451 | { |
| 9452 | result = dns_dnssec_verify(keyname, |
| 9453 | &kfetch->dnskeyset, |
| 9454 | dstkey, false, 0, mctx, |
| 9455 | &sigrr, |
| 9456 | dns_fixedname_name(&fixed)); |
| 9457 | |
| 9458 | dnssec_log(kfetch->zone, ISC_LOG_DEBUG(3), |
| 9459 | "Confirm revoked DNSKEY is self-signed: %s" , |
| 9460 | dns_result_totext(result)); |
| 9461 | |
| 9462 | if (result == ISC_R_SUCCESS) { |
| 9463 | answer = true; |
| 9464 | break; |
| 9465 | } |
| 9466 | } |
| 9467 | } |
| 9468 | |
| 9469 | dst_key_free(&dstkey); |
| 9470 | return (answer); |
| 9471 | } |
| 9472 | |
| 9473 | /* |
| 9474 | * A DNSKEY set has been fetched from the zone apex of a zone whose trust |
| 9475 | * anchors are being managed; scan the keyset, and update the key zone and the |
| 9476 | * local trust anchors according to RFC5011. |
| 9477 | */ |
| 9478 | static void |
| 9479 | keyfetch_done(isc_task_t *task, isc_event_t *event) { |
| 9480 | isc_result_t result, eresult; |
| 9481 | dns_fetchevent_t *devent; |
| 9482 | dns_keyfetch_t *kfetch; |
| 9483 | dns_zone_t *zone; |
| 9484 | isc_mem_t *mctx = NULL; |
| 9485 | dns_keytable_t *secroots = NULL; |
| 9486 | dns_dbversion_t *ver = NULL; |
| 9487 | dns_diff_t diff; |
| 9488 | bool alldone = false; |
| 9489 | bool commit = false; |
| 9490 | dns_name_t *keyname; |
| 9491 | dns_rdata_t sigrr = DNS_RDATA_INIT; |
| 9492 | dns_rdata_t dnskeyrr = DNS_RDATA_INIT; |
| 9493 | dns_rdata_t keydatarr = DNS_RDATA_INIT; |
| 9494 | dns_rdata_rrsig_t sig; |
| 9495 | dns_rdata_dnskey_t dnskey; |
| 9496 | dns_rdata_keydata_t keydata; |
| 9497 | bool initializing; |
| 9498 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 9499 | unsigned char key_buf[4096]; |
| 9500 | isc_buffer_t keyb; |
| 9501 | dst_key_t *dstkey; |
| 9502 | isc_stdtime_t now; |
| 9503 | int pending = 0; |
| 9504 | bool secure = false, initial = false; |
| 9505 | bool free_needed; |
| 9506 | |
| 9507 | UNUSED(task); |
| 9508 | INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE); |
| 9509 | INSIST(event->ev_arg != NULL); |
| 9510 | |
| 9511 | kfetch = event->ev_arg; |
| 9512 | zone = kfetch->zone; |
| 9513 | isc_mem_attach(zone->mctx, &mctx); |
| 9514 | keyname = dns_fixedname_name(&kfetch->name); |
| 9515 | |
| 9516 | devent = (dns_fetchevent_t *) event; |
| 9517 | eresult = devent->result; |
| 9518 | |
| 9519 | /* Free resources which are not of interest */ |
| 9520 | if (devent->node != NULL) { |
| 9521 | dns_db_detachnode(devent->db, &devent->node); |
| 9522 | } |
| 9523 | if (devent->db != NULL) { |
| 9524 | dns_db_detach(&devent->db); |
| 9525 | } |
| 9526 | isc_event_free(&event); |
| 9527 | dns_resolver_destroyfetch(&kfetch->fetch); |
| 9528 | |
| 9529 | LOCK_ZONE(zone); |
| 9530 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || zone->view == NULL) { |
| 9531 | goto cleanup; |
| 9532 | } |
| 9533 | |
| 9534 | isc_stdtime_get(&now); |
| 9535 | dns_name_format(keyname, namebuf, sizeof(namebuf)); |
| 9536 | |
| 9537 | result = dns_view_getsecroots(zone->view, &secroots); |
| 9538 | INSIST(result == ISC_R_SUCCESS); |
| 9539 | |
| 9540 | dns_diff_init(mctx, &diff); |
| 9541 | |
| 9542 | CHECK(dns_db_newversion(kfetch->db, &ver)); |
| 9543 | |
| 9544 | zone->refreshkeycount--; |
| 9545 | alldone = (zone->refreshkeycount == 0); |
| 9546 | |
| 9547 | if (alldone) { |
| 9548 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESHING); |
| 9549 | } |
| 9550 | |
| 9551 | dnssec_log(zone, ISC_LOG_DEBUG(3), |
| 9552 | "Returned from key fetch in keyfetch_done() for '%s': %s" , |
| 9553 | namebuf, dns_result_totext(eresult)); |
| 9554 | |
| 9555 | /* Fetch failed */ |
| 9556 | if (eresult != ISC_R_SUCCESS || |
| 9557 | !dns_rdataset_isassociated(&kfetch->dnskeyset)) |
| 9558 | { |
| 9559 | dnssec_log(zone, ISC_LOG_WARNING, |
| 9560 | "Unable to fetch DNSKEY set '%s': %s" , |
| 9561 | namebuf, dns_result_totext(eresult)); |
| 9562 | CHECK(minimal_update(kfetch, ver, &diff)); |
| 9563 | goto done; |
| 9564 | } |
| 9565 | |
| 9566 | /* No RRSIGs found */ |
| 9567 | if (!dns_rdataset_isassociated(&kfetch->dnskeysigset)) { |
| 9568 | dnssec_log(zone, ISC_LOG_WARNING, |
| 9569 | "No DNSKEY RRSIGs found for '%s': %s" , |
| 9570 | namebuf, dns_result_totext(eresult)); |
| 9571 | CHECK(minimal_update(kfetch, ver, &diff)); |
| 9572 | goto done; |
| 9573 | } |
| 9574 | |
| 9575 | /* |
| 9576 | * Clear any cached trust level, as we need to run validation |
| 9577 | * over again; trusted keys might have changed. |
| 9578 | */ |
| 9579 | kfetch->dnskeyset.trust = kfetch->dnskeysigset.trust = dns_trust_none; |
| 9580 | |
| 9581 | /* |
| 9582 | * Validate the dnskeyset against the current trusted keys. |
| 9583 | */ |
| 9584 | for (result = dns_rdataset_first(&kfetch->dnskeysigset); |
| 9585 | result == ISC_R_SUCCESS; |
| 9586 | result = dns_rdataset_next(&kfetch->dnskeysigset)) |
| 9587 | { |
| 9588 | dns_keynode_t *keynode = NULL; |
| 9589 | |
| 9590 | dns_rdata_reset(&sigrr); |
| 9591 | dns_rdataset_current(&kfetch->dnskeysigset, &sigrr); |
| 9592 | result = dns_rdata_tostruct(&sigrr, &sig, NULL); |
| 9593 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9594 | |
| 9595 | result = dns_keytable_find(secroots, keyname, &keynode); |
| 9596 | while (result == ISC_R_SUCCESS) { |
| 9597 | dns_keynode_t *nextnode = NULL; |
| 9598 | dns_fixedname_t fixed; |
| 9599 | dns_fixedname_init(&fixed); |
| 9600 | |
| 9601 | dstkey = dns_keynode_key(keynode); |
| 9602 | if (dstkey == NULL) { |
| 9603 | /* fail_secure() was called */ |
| 9604 | break; |
| 9605 | } |
| 9606 | |
| 9607 | if (dst_key_alg(dstkey) == sig.algorithm && |
| 9608 | dst_key_id(dstkey) == sig.keyid) |
| 9609 | { |
| 9610 | result = dns_dnssec_verify(keyname, |
| 9611 | &kfetch->dnskeyset, |
| 9612 | dstkey, false, |
| 9613 | 0, |
| 9614 | zone->view->mctx, |
| 9615 | &sigrr, |
| 9616 | dns_fixedname_name( |
| 9617 | &fixed)); |
| 9618 | |
| 9619 | dnssec_log(zone, ISC_LOG_DEBUG(3), |
| 9620 | "Verifying DNSKEY set for zone " |
| 9621 | "'%s' using key %d/%d: %s" , |
| 9622 | namebuf, sig.keyid, sig.algorithm, |
| 9623 | dns_result_totext(result)); |
| 9624 | |
| 9625 | if (result == ISC_R_SUCCESS) { |
| 9626 | kfetch->dnskeyset.trust = |
| 9627 | dns_trust_secure; |
| 9628 | kfetch->dnskeysigset.trust = |
| 9629 | dns_trust_secure; |
| 9630 | secure = true; |
| 9631 | initial = dns_keynode_initial(keynode); |
| 9632 | dns_keynode_trust(keynode); |
| 9633 | break; |
| 9634 | } |
| 9635 | } |
| 9636 | |
| 9637 | result = dns_keytable_nextkeynode(secroots, |
| 9638 | keynode, &nextnode); |
| 9639 | dns_keytable_detachkeynode(secroots, &keynode); |
| 9640 | keynode = nextnode; |
| 9641 | } |
| 9642 | |
| 9643 | if (keynode != NULL) { |
| 9644 | dns_keytable_detachkeynode(secroots, &keynode); |
| 9645 | } |
| 9646 | |
| 9647 | if (secure) { |
| 9648 | break; |
| 9649 | } |
| 9650 | } |
| 9651 | |
| 9652 | /* |
| 9653 | * If we were not able to verify the answer using the current |
| 9654 | * trusted keys then all we can do is look at any revoked keys. |
| 9655 | */ |
| 9656 | if (!secure) { |
| 9657 | dnssec_log(zone, ISC_LOG_INFO, |
| 9658 | "DNSKEY set for zone '%s' could not be verified " |
| 9659 | "with current keys" , namebuf); |
| 9660 | } |
| 9661 | |
| 9662 | /* |
| 9663 | * First scan keydataset to find keys that are not in dnskeyset |
| 9664 | * - Missing keys which are not scheduled for removal, |
| 9665 | * log a warning |
| 9666 | * - Missing keys which are scheduled for removal and |
| 9667 | * the remove hold-down timer has completed should |
| 9668 | * be removed from the key zone |
| 9669 | * - Missing keys whose acceptance timers have not yet |
| 9670 | * completed, log a warning and reset the acceptance |
| 9671 | * timer to 30 days in the future |
| 9672 | * - All keys not being removed have their refresh timers |
| 9673 | * updated |
| 9674 | */ |
| 9675 | initializing = true; |
| 9676 | for (result = dns_rdataset_first(&kfetch->keydataset); |
| 9677 | result == ISC_R_SUCCESS; |
| 9678 | result = dns_rdataset_next(&kfetch->keydataset)) |
| 9679 | { |
| 9680 | dns_keytag_t keytag; |
| 9681 | |
| 9682 | dns_rdata_reset(&keydatarr); |
| 9683 | dns_rdataset_current(&kfetch->keydataset, &keydatarr); |
| 9684 | result = dns_rdata_tostruct(&keydatarr, &keydata, NULL); |
| 9685 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9686 | |
| 9687 | dns_keydata_todnskey(&keydata, &dnskey, NULL); |
| 9688 | result = compute_tag(keyname, &dnskey, mctx, &keytag); |
| 9689 | if (result != ISC_R_SUCCESS) { |
| 9690 | /* |
| 9691 | * Skip if we cannot compute the key tag. |
| 9692 | * This may happen if the algorithm is unsupported |
| 9693 | */ |
| 9694 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 9695 | "Cannot compute tag for key in zone %s: %s " |
| 9696 | "(skipping)" , |
| 9697 | namebuf, dns_result_totext(result)); |
| 9698 | continue; |
| 9699 | } |
| 9700 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9701 | |
| 9702 | /* |
| 9703 | * If any keydata record has a nonzero add holddown, then |
| 9704 | * there was a pre-existing trust anchor for this domain; |
| 9705 | * that means we are *not* initializing it and shouldn't |
| 9706 | * automatically trust all the keys we find at the zone apex. |
| 9707 | */ |
| 9708 | initializing = initializing && (keydata.addhd == 0); |
| 9709 | |
| 9710 | if (! matchkey(&kfetch->dnskeyset, &keydatarr)) { |
| 9711 | bool deletekey = false; |
| 9712 | |
| 9713 | if (!secure) { |
| 9714 | if (keydata.removehd != 0 && |
| 9715 | keydata.removehd <= now) |
| 9716 | { |
| 9717 | deletekey = true; |
| 9718 | } |
| 9719 | } else if (keydata.addhd == 0) { |
| 9720 | deletekey = true; |
| 9721 | } else if (keydata.addhd > now) { |
| 9722 | dnssec_log(zone, ISC_LOG_INFO, |
| 9723 | "Pending key %d for zone %s " |
| 9724 | "unexpectedly missing " |
| 9725 | "restarting 30-day acceptance " |
| 9726 | "timer" , keytag, namebuf); |
| 9727 | if (keydata.addhd < now + dns_zone_mkey_month) { |
| 9728 | keydata.addhd = |
| 9729 | now + dns_zone_mkey_month; |
| 9730 | } |
| 9731 | keydata.refresh = refresh_time(kfetch, false); |
| 9732 | } else if (keydata.removehd == 0) { |
| 9733 | dnssec_log(zone, ISC_LOG_INFO, |
| 9734 | "Active key %d for zone %s " |
| 9735 | "unexpectedly missing" , |
| 9736 | keytag, namebuf); |
| 9737 | keydata.refresh = now + dns_zone_mkey_hour; |
| 9738 | } else if (keydata.removehd <= now) { |
| 9739 | deletekey = true; |
| 9740 | dnssec_log(zone, ISC_LOG_INFO, |
| 9741 | "Revoked key %d for zone %s " |
| 9742 | "missing: deleting from " |
| 9743 | "managed keys database" , |
| 9744 | keytag, namebuf); |
| 9745 | } else { |
| 9746 | keydata.refresh = refresh_time(kfetch, false); |
| 9747 | } |
| 9748 | |
| 9749 | if (secure || deletekey) { |
| 9750 | /* Delete old version */ |
| 9751 | CHECK(update_one_rr(kfetch->db, ver, &diff, |
| 9752 | DNS_DIFFOP_DEL, keyname, 0, |
| 9753 | &keydatarr)); |
| 9754 | } |
| 9755 | |
| 9756 | if (!secure || deletekey) { |
| 9757 | continue; |
| 9758 | } |
| 9759 | |
| 9760 | dns_rdata_reset(&keydatarr); |
| 9761 | isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); |
| 9762 | dns_rdata_fromstruct(&keydatarr, zone->rdclass, |
| 9763 | dns_rdatatype_keydata, |
| 9764 | &keydata, &keyb); |
| 9765 | |
| 9766 | /* Insert updated version */ |
| 9767 | CHECK(update_one_rr(kfetch->db, ver, &diff, |
| 9768 | DNS_DIFFOP_ADD, keyname, 0, |
| 9769 | &keydatarr)); |
| 9770 | |
| 9771 | set_refreshkeytimer(zone, &keydata, now, false); |
| 9772 | } |
| 9773 | } |
| 9774 | |
| 9775 | /* |
| 9776 | * Next scan dnskeyset: |
| 9777 | * - If new keys are found (i.e., lacking a match in keydataset) |
| 9778 | * add them to the key zone and set the acceptance timer |
| 9779 | * to 30 days in the future (or to immediately if we've |
| 9780 | * determined that we're initializing the zone for the |
| 9781 | * first time) |
| 9782 | * - Previously-known keys that have been revoked |
| 9783 | * must be scheduled for removal from the key zone (or, |
| 9784 | * if they hadn't been accepted as trust anchors yet |
| 9785 | * anyway, removed at once) |
| 9786 | * - Previously-known unrevoked keys whose acceptance timers |
| 9787 | * have completed are promoted to trust anchors |
| 9788 | * - All keys not being removed have their refresh |
| 9789 | * timers updated |
| 9790 | */ |
| 9791 | for (result = dns_rdataset_first(&kfetch->dnskeyset); |
| 9792 | result == ISC_R_SUCCESS; |
| 9793 | result = dns_rdataset_next(&kfetch->dnskeyset)) |
| 9794 | { |
| 9795 | bool revoked = false; |
| 9796 | bool newkey = false; |
| 9797 | bool updatekey = false; |
| 9798 | bool deletekey = false; |
| 9799 | bool trustkey = false; |
| 9800 | dns_keytag_t keytag; |
| 9801 | |
| 9802 | dns_rdata_reset(&dnskeyrr); |
| 9803 | dns_rdataset_current(&kfetch->dnskeyset, &dnskeyrr); |
| 9804 | result = dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); |
| 9805 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9806 | |
| 9807 | /* Skip ZSK's */ |
| 9808 | if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0) { |
| 9809 | continue; |
| 9810 | } |
| 9811 | |
| 9812 | result = compute_tag(keyname, &dnskey, mctx, &keytag); |
| 9813 | if (result != ISC_R_SUCCESS) { |
| 9814 | /* |
| 9815 | * Skip if we cannot compute the key tag. |
| 9816 | * This may happen if the algorithm is unsupported |
| 9817 | */ |
| 9818 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 9819 | "Cannot compute tag for key in zone %s: %s " |
| 9820 | "(skipping)" , |
| 9821 | namebuf, dns_result_totext(result)); |
| 9822 | continue; |
| 9823 | } |
| 9824 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9825 | |
| 9826 | revoked = ((dnskey.flags & DNS_KEYFLAG_REVOKE) != 0); |
| 9827 | |
| 9828 | if (matchkey(&kfetch->keydataset, &dnskeyrr)) { |
| 9829 | dns_rdata_reset(&keydatarr); |
| 9830 | dns_rdataset_current(&kfetch->keydataset, &keydatarr); |
| 9831 | result = dns_rdata_tostruct(&keydatarr, &keydata, NULL); |
| 9832 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 9833 | |
| 9834 | if (revoked && revocable(kfetch, &keydata)) { |
| 9835 | if (keydata.addhd > now) { |
| 9836 | /* |
| 9837 | * Key wasn't trusted yet, and now |
| 9838 | * it's been revoked? Just remove it |
| 9839 | */ |
| 9840 | deletekey = true; |
| 9841 | dnssec_log(zone, ISC_LOG_INFO, |
| 9842 | "Pending key %d for " |
| 9843 | "zone %s is now revoked: " |
| 9844 | "deleting from the " |
| 9845 | "managed keys database" , |
| 9846 | keytag, namebuf); |
| 9847 | } else if (keydata.removehd == 0) { |
| 9848 | /* |
| 9849 | * Remove key from secroots. |
| 9850 | */ |
| 9851 | dns_view_untrust(zone->view, keyname, |
| 9852 | &dnskey, mctx); |
| 9853 | |
| 9854 | /* If initializing, delete now */ |
| 9855 | if (keydata.addhd == 0) { |
| 9856 | deletekey = true; |
| 9857 | } else { |
| 9858 | keydata.removehd = now + |
| 9859 | dns_zone_mkey_month; |
| 9860 | keydata.flags |= |
| 9861 | DNS_KEYFLAG_REVOKE; |
| 9862 | } |
| 9863 | |
| 9864 | dnssec_log(zone, ISC_LOG_INFO, |
| 9865 | "Trusted key %d for " |
| 9866 | "zone %s is now revoked" , |
| 9867 | keytag, namebuf); |
| 9868 | } else if (keydata.removehd < now) { |
| 9869 | /* Scheduled for removal */ |
| 9870 | deletekey = true; |
| 9871 | |
| 9872 | dnssec_log(zone, ISC_LOG_INFO, |
| 9873 | "Revoked key %d for " |
| 9874 | "zone %s removal timer " |
| 9875 | "complete: deleting from " |
| 9876 | "the managed keys database" , |
| 9877 | keytag, namebuf); |
| 9878 | } |
| 9879 | } else if (revoked && keydata.removehd == 0) { |
| 9880 | dnssec_log(zone, ISC_LOG_WARNING, |
| 9881 | "Active key %d for zone " |
| 9882 | "%s is revoked but " |
| 9883 | "did not self-sign; " |
| 9884 | "ignoring" , keytag, namebuf); |
| 9885 | continue; |
| 9886 | } else if (secure) { |
| 9887 | if (keydata.removehd != 0) { |
| 9888 | /* |
| 9889 | * Key isn't revoked--but it |
| 9890 | * seems it used to be. |
| 9891 | * Remove it now and add it |
| 9892 | * back as if it were a fresh key, |
| 9893 | * with a 30-day acceptance timer. |
| 9894 | */ |
| 9895 | deletekey = true; |
| 9896 | newkey = true; |
| 9897 | keydata.removehd = 0; |
| 9898 | keydata.addhd = |
| 9899 | now + dns_zone_mkey_month; |
| 9900 | |
| 9901 | dnssec_log(zone, ISC_LOG_INFO, |
| 9902 | "Revoked key %d for " |
| 9903 | "zone %s has returned: " |
| 9904 | "starting 30-day " |
| 9905 | "acceptance timer" , |
| 9906 | keytag, namebuf); |
| 9907 | } else if (keydata.addhd > now) { |
| 9908 | pending++; |
| 9909 | } else if (keydata.addhd == 0) { |
| 9910 | keydata.addhd = now; |
| 9911 | } |
| 9912 | |
| 9913 | if (keydata.addhd <= now) { |
| 9914 | trustkey = true; |
| 9915 | dnssec_log(zone, ISC_LOG_INFO, |
| 9916 | "Key %d for zone %s " |
| 9917 | "is now trusted (%s)" , |
| 9918 | keytag, namebuf, |
| 9919 | initial |
| 9920 | ? "initializing key " |
| 9921 | "verified" |
| 9922 | : "acceptance timer " |
| 9923 | "complete" ); |
| 9924 | } |
| 9925 | } else if (keydata.addhd > now) { |
| 9926 | /* |
| 9927 | * Not secure, and key is pending: |
| 9928 | * reset the acceptance timer |
| 9929 | */ |
| 9930 | pending++; |
| 9931 | keydata.addhd = now + dns_zone_mkey_month; |
| 9932 | dnssec_log(zone, ISC_LOG_INFO, |
| 9933 | "Pending key %d " |
| 9934 | "for zone %s was " |
| 9935 | "not validated: restarting " |
| 9936 | "30-day acceptance timer" , |
| 9937 | keytag, namebuf); |
| 9938 | } |
| 9939 | |
| 9940 | if (!deletekey && !newkey) { |
| 9941 | updatekey = true; |
| 9942 | } |
| 9943 | } else if (secure) { |
| 9944 | /* |
| 9945 | * Key wasn't in the key zone but it's |
| 9946 | * revoked now anyway, so just skip it |
| 9947 | */ |
| 9948 | if (revoked) { |
| 9949 | continue; |
| 9950 | } |
| 9951 | |
| 9952 | /* Key wasn't in the key zone: add it */ |
| 9953 | newkey = true; |
| 9954 | |
| 9955 | if (initializing) { |
| 9956 | dnssec_log(zone, ISC_LOG_WARNING, |
| 9957 | "Initializing automatic trust " |
| 9958 | "anchor management for zone '%s'; " |
| 9959 | "DNSKEY ID %d is now trusted, " |
| 9960 | "waiving the normal 30-day " |
| 9961 | "waiting period." , |
| 9962 | namebuf, keytag); |
| 9963 | trustkey = true; |
| 9964 | } else { |
| 9965 | dnssec_log(zone, ISC_LOG_INFO, |
| 9966 | "New key %d observed " |
| 9967 | "for zone '%s': " |
| 9968 | "starting 30-day " |
| 9969 | "acceptance timer" , |
| 9970 | keytag, namebuf); |
| 9971 | } |
| 9972 | } else { |
| 9973 | /* |
| 9974 | * No previously known key, and the key is not |
| 9975 | * secure, so skip it. |
| 9976 | */ |
| 9977 | continue; |
| 9978 | } |
| 9979 | |
| 9980 | /* Delete old version */ |
| 9981 | if (deletekey || !newkey) { |
| 9982 | CHECK(update_one_rr(kfetch->db, ver, &diff, |
| 9983 | DNS_DIFFOP_DEL, keyname, 0, |
| 9984 | &keydatarr)); |
| 9985 | } |
| 9986 | |
| 9987 | if (updatekey) { |
| 9988 | /* Set refresh timer */ |
| 9989 | keydata.refresh = refresh_time(kfetch, false); |
| 9990 | dns_rdata_reset(&keydatarr); |
| 9991 | isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); |
| 9992 | dns_rdata_fromstruct(&keydatarr, zone->rdclass, |
| 9993 | dns_rdatatype_keydata, |
| 9994 | &keydata, &keyb); |
| 9995 | |
| 9996 | /* Insert updated version */ |
| 9997 | CHECK(update_one_rr(kfetch->db, ver, &diff, |
| 9998 | DNS_DIFFOP_ADD, keyname, 0, |
| 9999 | &keydatarr)); |
| 10000 | } else if (newkey) { |
| 10001 | /* Convert DNSKEY to KEYDATA */ |
| 10002 | result = dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); |
| 10003 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 10004 | dns_keydata_fromdnskey(&keydata, &dnskey, 0, 0, 0, |
| 10005 | NULL); |
| 10006 | keydata.addhd = initializing |
| 10007 | ? now : now + dns_zone_mkey_month; |
| 10008 | keydata.refresh = refresh_time(kfetch, false); |
| 10009 | dns_rdata_reset(&keydatarr); |
| 10010 | isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); |
| 10011 | dns_rdata_fromstruct(&keydatarr, zone->rdclass, |
| 10012 | dns_rdatatype_keydata, |
| 10013 | &keydata, &keyb); |
| 10014 | |
| 10015 | /* Insert into key zone */ |
| 10016 | CHECK(update_one_rr(kfetch->db, ver, &diff, |
| 10017 | DNS_DIFFOP_ADD, keyname, 0, |
| 10018 | &keydatarr)); |
| 10019 | } |
| 10020 | |
| 10021 | if (trustkey) { |
| 10022 | /* Trust this key. */ |
| 10023 | result = dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); |
| 10024 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 10025 | trust_key(zone, keyname, &dnskey, false, mctx); |
| 10026 | } |
| 10027 | |
| 10028 | if (secure && !deletekey) { |
| 10029 | INSIST(newkey || updatekey); |
| 10030 | set_refreshkeytimer(zone, &keydata, now, false); |
| 10031 | } |
| 10032 | } |
| 10033 | |
| 10034 | /* |
| 10035 | * RFC5011 says, "A trust point that has all of its trust anchors |
| 10036 | * revoked is considered deleted and is treated as if the trust |
| 10037 | * point was never configured." But if someone revoked their |
| 10038 | * active key before the standby was trusted, that would mean the |
| 10039 | * zone would suddenly be nonsecured. We avoid this by checking to |
| 10040 | * see if there's pending keydata. If so, we put a null key in |
| 10041 | * the security roots; then all queries to the zone will fail. |
| 10042 | */ |
| 10043 | if (pending != 0) { |
| 10044 | fail_secure(zone, keyname); |
| 10045 | } |
| 10046 | |
| 10047 | done: |
| 10048 | if (!ISC_LIST_EMPTY(diff.tuples)) { |
| 10049 | /* Write changes to journal file. */ |
| 10050 | CHECK(update_soa_serial(kfetch->db, ver, &diff, mctx, |
| 10051 | zone->updatemethod)); |
| 10052 | CHECK(zone_journal(zone, &diff, NULL, "keyfetch_done" )); |
| 10053 | commit = true; |
| 10054 | |
| 10055 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); |
| 10056 | zone_needdump(zone, 30); |
| 10057 | } else if (result == ISC_R_NOMORE) { |
| 10058 | /* |
| 10059 | * If "updatekey" was true for all keys found in the DNSKEY |
| 10060 | * response and the previous update of those keys happened |
| 10061 | * during the same second (only possible if a key refresh was |
| 10062 | * externally triggered), it may happen that all relevant |
| 10063 | * update_one_rr() calls will return ISC_R_SUCCESS, but |
| 10064 | * diff.tuples will remain empty. Reset result to |
| 10065 | * ISC_R_SUCCESS to prevent a bogus warning from being logged. |
| 10066 | */ |
| 10067 | result = ISC_R_SUCCESS; |
| 10068 | } |
| 10069 | |
| 10070 | failure: |
| 10071 | if (result != ISC_R_SUCCESS) { |
| 10072 | dnssec_log(zone, ISC_LOG_ERROR, |
| 10073 | "error during managed-keys processing (%s): " |
| 10074 | "DNSSEC validation may be at risk" , |
| 10075 | isc_result_totext(result)); |
| 10076 | } |
| 10077 | dns_diff_clear(&diff); |
| 10078 | if (ver != NULL) { |
| 10079 | dns_db_closeversion(kfetch->db, &ver, commit); |
| 10080 | } |
| 10081 | |
| 10082 | cleanup: |
| 10083 | dns_db_detach(&kfetch->db); |
| 10084 | |
| 10085 | INSIST(zone->irefs > 0); |
| 10086 | zone->irefs--; |
| 10087 | kfetch->zone = NULL; |
| 10088 | |
| 10089 | if (dns_rdataset_isassociated(&kfetch->keydataset)) { |
| 10090 | dns_rdataset_disassociate(&kfetch->keydataset); |
| 10091 | } |
| 10092 | if (dns_rdataset_isassociated(&kfetch->dnskeyset)) { |
| 10093 | dns_rdataset_disassociate(&kfetch->dnskeyset); |
| 10094 | } |
| 10095 | if (dns_rdataset_isassociated(&kfetch->dnskeysigset)) { |
| 10096 | dns_rdataset_disassociate(&kfetch->dnskeysigset); |
| 10097 | } |
| 10098 | |
| 10099 | dns_name_free(keyname, mctx); |
| 10100 | isc_mem_put(mctx, kfetch, sizeof(dns_keyfetch_t)); |
| 10101 | isc_mem_detach(&mctx); |
| 10102 | |
| 10103 | if (secroots != NULL) { |
| 10104 | dns_keytable_detach(&secroots); |
| 10105 | } |
| 10106 | |
| 10107 | free_needed = exit_check(zone); |
| 10108 | UNLOCK_ZONE(zone); |
| 10109 | if (free_needed) { |
| 10110 | zone_free(zone); |
| 10111 | } |
| 10112 | |
| 10113 | INSIST(ver == NULL); |
| 10114 | } |
| 10115 | |
| 10116 | /* |
| 10117 | * Refresh the data in the key zone. Initiate a fetch to get new DNSKEY |
| 10118 | * records from the zone apex. |
| 10119 | */ |
| 10120 | static void |
| 10121 | zone_refreshkeys(dns_zone_t *zone) { |
| 10122 | const char me[] = "zone_refreshkeys" ; |
| 10123 | isc_result_t result; |
| 10124 | dns_rriterator_t rrit; |
| 10125 | dns_db_t *db = NULL; |
| 10126 | dns_dbversion_t *ver = NULL; |
| 10127 | dns_diff_t diff; |
| 10128 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 10129 | dns_rdata_keydata_t kd; |
| 10130 | isc_stdtime_t now; |
| 10131 | bool commit = false; |
| 10132 | bool fetching = false, fetch_err = false; |
| 10133 | bool timerset = false; |
| 10134 | |
| 10135 | ENTER; |
| 10136 | REQUIRE(zone->db != NULL); |
| 10137 | |
| 10138 | isc_stdtime_get(&now); |
| 10139 | |
| 10140 | LOCK_ZONE(zone); |
| 10141 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { |
| 10142 | isc_time_settoepoch(&zone->refreshkeytime); |
| 10143 | UNLOCK_ZONE(zone); |
| 10144 | return; |
| 10145 | } |
| 10146 | |
| 10147 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 10148 | dns_db_attach(zone->db, &db); |
| 10149 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 10150 | |
| 10151 | dns_diff_init(zone->mctx, &diff); |
| 10152 | |
| 10153 | CHECK(dns_db_newversion(db, &ver)); |
| 10154 | |
| 10155 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESHING); |
| 10156 | |
| 10157 | dns_rriterator_init(&rrit, db, ver, 0); |
| 10158 | for (result = dns_rriterator_first(&rrit); |
| 10159 | result == ISC_R_SUCCESS; |
| 10160 | result = dns_rriterator_nextrrset(&rrit)) |
| 10161 | { |
| 10162 | isc_stdtime_t timer = 0xffffffff; |
| 10163 | dns_name_t *name = NULL, *kname = NULL; |
| 10164 | dns_rdataset_t *kdset = NULL; |
| 10165 | dns_keyfetch_t *kfetch; |
| 10166 | uint32_t ttl; |
| 10167 | |
| 10168 | dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL); |
| 10169 | if (kdset == NULL || kdset->type != dns_rdatatype_keydata || |
| 10170 | !dns_rdataset_isassociated(kdset)) |
| 10171 | { |
| 10172 | continue; |
| 10173 | } |
| 10174 | |
| 10175 | /* |
| 10176 | * Scan the stored keys looking for ones that need |
| 10177 | * removal or refreshing |
| 10178 | */ |
| 10179 | for (result = dns_rdataset_first(kdset); |
| 10180 | result == ISC_R_SUCCESS; |
| 10181 | result = dns_rdataset_next(kdset)) |
| 10182 | { |
| 10183 | dns_rdata_reset(&rdata); |
| 10184 | dns_rdataset_current(kdset, &rdata); |
| 10185 | result = dns_rdata_tostruct(&rdata, &kd, NULL); |
| 10186 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 10187 | |
| 10188 | /* Removal timer expired? */ |
| 10189 | if (kd.removehd != 0 && kd.removehd < now) { |
| 10190 | CHECK(update_one_rr(db, ver, &diff, |
| 10191 | DNS_DIFFOP_DEL, name, ttl, |
| 10192 | &rdata)); |
| 10193 | continue; |
| 10194 | } |
| 10195 | |
| 10196 | /* Acceptance timer expired? */ |
| 10197 | if (kd.addhd <= now) { |
| 10198 | timer = kd.addhd; |
| 10199 | } |
| 10200 | |
| 10201 | /* Or do we just need to refresh the keyset? */ |
| 10202 | if (timer > kd.refresh) { |
| 10203 | timer = kd.refresh; |
| 10204 | } |
| 10205 | |
| 10206 | set_refreshkeytimer(zone, &kd, now, false); |
| 10207 | timerset = true; |
| 10208 | } |
| 10209 | |
| 10210 | if (timer > now) { |
| 10211 | continue; |
| 10212 | } |
| 10213 | |
| 10214 | kfetch = isc_mem_get(zone->mctx, sizeof(dns_keyfetch_t)); |
| 10215 | if (kfetch == NULL) { |
| 10216 | fetch_err = true; |
| 10217 | goto failure; |
| 10218 | } |
| 10219 | |
| 10220 | zone->refreshkeycount++; |
| 10221 | kfetch->zone = zone; |
| 10222 | zone->irefs++; |
| 10223 | INSIST(zone->irefs != 0); |
| 10224 | kname = dns_fixedname_initname(&kfetch->name); |
| 10225 | dns_name_dup(name, zone->mctx, kname); |
| 10226 | dns_rdataset_init(&kfetch->dnskeyset); |
| 10227 | dns_rdataset_init(&kfetch->dnskeysigset); |
| 10228 | dns_rdataset_init(&kfetch->keydataset); |
| 10229 | dns_rdataset_clone(kdset, &kfetch->keydataset); |
| 10230 | kfetch->db = NULL; |
| 10231 | dns_db_attach(db, &kfetch->db); |
| 10232 | kfetch->fetch = NULL; |
| 10233 | |
| 10234 | if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) { |
| 10235 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 10236 | dns_name_format(kname, namebuf, |
| 10237 | sizeof(namebuf)); |
| 10238 | dnssec_log(zone, ISC_LOG_DEBUG(3), |
| 10239 | "Creating key fetch in " |
| 10240 | "zone_refreshkeys() for '%s'" , |
| 10241 | namebuf); |
| 10242 | } |
| 10243 | |
| 10244 | /* |
| 10245 | * Use of DNS_FETCHOPT_NOCACHED is essential here. If it is |
| 10246 | * not set and the cache still holds a non-expired, validated |
| 10247 | * version of the RRset being queried for by the time the |
| 10248 | * response is received, the cached RRset will be passed to |
| 10249 | * keyfetch_done() instead of the one received in the response |
| 10250 | * as the latter will have a lower trust level due to not being |
| 10251 | * validated until keyfetch_done() is called. |
| 10252 | */ |
| 10253 | |
| 10254 | #ifdef ENABLE_AFL |
| 10255 | if (dns_fuzzing_resolver == false) { |
| 10256 | #endif |
| 10257 | result = dns_resolver_createfetch(zone->view->resolver, |
| 10258 | kname, dns_rdatatype_dnskey, |
| 10259 | NULL, NULL, NULL, NULL, 0, |
| 10260 | DNS_FETCHOPT_NOVALIDATE | |
| 10261 | DNS_FETCHOPT_UNSHARED | |
| 10262 | DNS_FETCHOPT_NOCACHED, |
| 10263 | 0, NULL, zone->task, |
| 10264 | keyfetch_done, kfetch, |
| 10265 | &kfetch->dnskeyset, |
| 10266 | &kfetch->dnskeysigset, |
| 10267 | &kfetch->fetch); |
| 10268 | #ifdef ENABLE_AFL |
| 10269 | } else { |
| 10270 | result = ISC_R_FAILURE; |
| 10271 | } |
| 10272 | #endif |
| 10273 | if (result == ISC_R_SUCCESS) { |
| 10274 | fetching = true; |
| 10275 | } else { |
| 10276 | zone->refreshkeycount--; |
| 10277 | zone->irefs--; |
| 10278 | dns_db_detach(&kfetch->db); |
| 10279 | dns_rdataset_disassociate(&kfetch->keydataset); |
| 10280 | dns_name_free(kname, zone->mctx); |
| 10281 | isc_mem_put(zone->mctx, kfetch, sizeof(dns_keyfetch_t)); |
| 10282 | dnssec_log(zone, ISC_LOG_WARNING, |
| 10283 | "Failed to create fetch for DNSKEY update" ); |
| 10284 | fetch_err = true; |
| 10285 | } |
| 10286 | } |
| 10287 | if (!ISC_LIST_EMPTY(diff.tuples)) { |
| 10288 | CHECK(update_soa_serial(db, ver, &diff, zone->mctx, |
| 10289 | zone->updatemethod)); |
| 10290 | CHECK(zone_journal(zone, &diff, NULL, "zone_refreshkeys" )); |
| 10291 | commit = true; |
| 10292 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); |
| 10293 | zone_needdump(zone, 30); |
| 10294 | } |
| 10295 | |
| 10296 | failure: |
| 10297 | if (fetch_err) { |
| 10298 | /* |
| 10299 | * Error during a key fetch; retry in an hour. |
| 10300 | */ |
| 10301 | isc_time_t timenow, timethen; |
| 10302 | char timebuf[80]; |
| 10303 | |
| 10304 | TIME_NOW(&timenow); |
| 10305 | DNS_ZONE_TIME_ADD(&timenow, dns_zone_mkey_hour, &timethen); |
| 10306 | zone->refreshkeytime = timethen; |
| 10307 | zone_settimer(zone, &timenow); |
| 10308 | |
| 10309 | isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80); |
| 10310 | dnssec_log(zone, ISC_LOG_DEBUG(1), "retry key refresh: %s" , |
| 10311 | timebuf); |
| 10312 | } else if (!timerset) { |
| 10313 | isc_time_settoepoch(&zone->refreshkeytime); |
| 10314 | } |
| 10315 | |
| 10316 | if (!fetching) { |
| 10317 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESHING); |
| 10318 | } |
| 10319 | |
| 10320 | dns_diff_clear(&diff); |
| 10321 | if (ver != NULL) { |
| 10322 | dns_rriterator_destroy(&rrit); |
| 10323 | dns_db_closeversion(db, &ver, commit); |
| 10324 | } |
| 10325 | dns_db_detach(&db); |
| 10326 | |
| 10327 | UNLOCK_ZONE(zone); |
| 10328 | |
| 10329 | INSIST(ver == NULL); |
| 10330 | } |
| 10331 | |
| 10332 | static void |
| 10333 | zone_maintenance(dns_zone_t *zone) { |
| 10334 | const char me[] = "zone_maintenance" ; |
| 10335 | isc_time_t now; |
| 10336 | isc_result_t result; |
| 10337 | bool dumping, load_pending; |
| 10338 | |
| 10339 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10340 | ENTER; |
| 10341 | |
| 10342 | /* |
| 10343 | * Are we pending load/reload? |
| 10344 | */ |
| 10345 | LOCK_ZONE(zone); |
| 10346 | load_pending = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING); |
| 10347 | UNLOCK_ZONE(zone); |
| 10348 | |
| 10349 | if (load_pending) { |
| 10350 | return; |
| 10351 | } |
| 10352 | |
| 10353 | /* |
| 10354 | * Configuring the view of this zone may have |
| 10355 | * failed, for example because the config file |
| 10356 | * had a syntax error. In that case, the view |
| 10357 | * adb or resolver will be NULL, and we had better not try |
| 10358 | * to do further maintenance on it. |
| 10359 | */ |
| 10360 | if (zone->view == NULL || zone->view->adb == NULL) |
| 10361 | return; |
| 10362 | |
| 10363 | TIME_NOW(&now); |
| 10364 | |
| 10365 | /* |
| 10366 | * Expire check. |
| 10367 | */ |
| 10368 | switch (zone->type) { |
| 10369 | case dns_zone_redirect: |
| 10370 | if (zone->masters == NULL) |
| 10371 | break; |
| 10372 | /* FALLTHROUGH */ |
| 10373 | case dns_zone_slave: |
| 10374 | case dns_zone_mirror: |
| 10375 | case dns_zone_stub: |
| 10376 | LOCK_ZONE(zone); |
| 10377 | if (isc_time_compare(&now, &zone->expiretime) >= 0 && |
| 10378 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { |
| 10379 | zone_expire(zone); |
| 10380 | zone->refreshtime = now; |
| 10381 | } |
| 10382 | UNLOCK_ZONE(zone); |
| 10383 | break; |
| 10384 | default: |
| 10385 | break; |
| 10386 | } |
| 10387 | |
| 10388 | /* |
| 10389 | * Up to date check. |
| 10390 | */ |
| 10391 | switch (zone->type) { |
| 10392 | case dns_zone_redirect: |
| 10393 | if (zone->masters == NULL) |
| 10394 | break; |
| 10395 | /* FALLTHROUGH */ |
| 10396 | case dns_zone_slave: |
| 10397 | case dns_zone_mirror: |
| 10398 | case dns_zone_stub: |
| 10399 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH) && |
| 10400 | isc_time_compare(&now, &zone->refreshtime) >= 0) |
| 10401 | dns_zone_refresh(zone); |
| 10402 | break; |
| 10403 | default: |
| 10404 | break; |
| 10405 | } |
| 10406 | |
| 10407 | /* |
| 10408 | * Slaves send notifies before backing up to disk, masters after. |
| 10409 | */ |
| 10410 | if ((zone->type == dns_zone_slave || zone->type == dns_zone_mirror) && |
| 10411 | (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) || |
| 10412 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY)) && |
| 10413 | isc_time_compare(&now, &zone->notifytime) >= 0) |
| 10414 | zone_notify(zone, &now); |
| 10415 | |
| 10416 | /* |
| 10417 | * Do we need to consolidate the backing store? |
| 10418 | */ |
| 10419 | switch (zone->type) { |
| 10420 | case dns_zone_master: |
| 10421 | case dns_zone_slave: |
| 10422 | case dns_zone_mirror: |
| 10423 | case dns_zone_key: |
| 10424 | case dns_zone_redirect: |
| 10425 | case dns_zone_stub: |
| 10426 | LOCK_ZONE(zone); |
| 10427 | if (zone->masterfile != NULL && |
| 10428 | isc_time_compare(&now, &zone->dumptime) >= 0 && |
| 10429 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && |
| 10430 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP)) { |
| 10431 | dumping = was_dumping(zone); |
| 10432 | } else |
| 10433 | dumping = true; |
| 10434 | UNLOCK_ZONE(zone); |
| 10435 | if (!dumping) { |
| 10436 | result = zone_dump(zone, true); /* task locked */ |
| 10437 | if (result != ISC_R_SUCCESS) |
| 10438 | dns_zone_log(zone, ISC_LOG_WARNING, |
| 10439 | "dump failed: %s" , |
| 10440 | dns_result_totext(result)); |
| 10441 | } |
| 10442 | break; |
| 10443 | default: |
| 10444 | break; |
| 10445 | } |
| 10446 | |
| 10447 | /* |
| 10448 | * Master/redirect zones send notifies now, if needed |
| 10449 | */ |
| 10450 | switch (zone->type) { |
| 10451 | case dns_zone_master: |
| 10452 | case dns_zone_redirect: |
| 10453 | if ((DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) || |
| 10454 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY))&& |
| 10455 | isc_time_compare(&now, &zone->notifytime) >= 0) |
| 10456 | zone_notify(zone, &now); |
| 10457 | default: |
| 10458 | break; |
| 10459 | } |
| 10460 | |
| 10461 | /* |
| 10462 | * Do we need to refresh keys? |
| 10463 | */ |
| 10464 | switch (zone->type) { |
| 10465 | case dns_zone_key: |
| 10466 | if (isc_time_compare(&now, &zone->refreshkeytime) >= 0) { |
| 10467 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && |
| 10468 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) { |
| 10469 | zone_refreshkeys(zone); |
| 10470 | } |
| 10471 | } |
| 10472 | break; |
| 10473 | case dns_zone_master: |
| 10474 | if (!isc_time_isepoch(&zone->refreshkeytime) && |
| 10475 | isc_time_compare(&now, &zone->refreshkeytime) >= 0 && |
| 10476 | zone->rss_event == NULL) |
| 10477 | zone_rekey(zone); |
| 10478 | default: |
| 10479 | break; |
| 10480 | } |
| 10481 | |
| 10482 | switch (zone->type) { |
| 10483 | case dns_zone_master: |
| 10484 | case dns_zone_redirect: |
| 10485 | case dns_zone_slave: |
| 10486 | /* |
| 10487 | * Do we need to sign/resign some RRsets? |
| 10488 | */ |
| 10489 | if (zone->rss_event != NULL) |
| 10490 | break; |
| 10491 | if (!isc_time_isepoch(&zone->signingtime) && |
| 10492 | isc_time_compare(&now, &zone->signingtime) >= 0) |
| 10493 | zone_sign(zone); |
| 10494 | else if (!isc_time_isepoch(&zone->resigntime) && |
| 10495 | isc_time_compare(&now, &zone->resigntime) >= 0) |
| 10496 | zone_resigninc(zone); |
| 10497 | else if (!isc_time_isepoch(&zone->nsec3chaintime) && |
| 10498 | isc_time_compare(&now, &zone->nsec3chaintime) >= 0) |
| 10499 | zone_nsec3chain(zone); |
| 10500 | /* |
| 10501 | * Do we need to issue a key expiry warning? |
| 10502 | */ |
| 10503 | if (!isc_time_isepoch(&zone->keywarntime) && |
| 10504 | isc_time_compare(&now, &zone->keywarntime) >= 0) |
| 10505 | set_key_expiry_warning(zone, zone->key_expiry, |
| 10506 | isc_time_seconds(&now)); |
| 10507 | break; |
| 10508 | |
| 10509 | default: |
| 10510 | break; |
| 10511 | } |
| 10512 | zone_settimer(zone, &now); |
| 10513 | } |
| 10514 | |
| 10515 | void |
| 10516 | dns_zone_markdirty(dns_zone_t *zone) { |
| 10517 | uint32_t serial; |
| 10518 | isc_result_t result = ISC_R_SUCCESS; |
| 10519 | dns_zone_t *secure = NULL; |
| 10520 | |
| 10521 | /* |
| 10522 | * Obtaining a lock on the zone->secure (see zone_send_secureserial) |
| 10523 | * could result in a deadlock due to a LOR so we will spin if we |
| 10524 | * can't obtain the both locks. |
| 10525 | */ |
| 10526 | again: |
| 10527 | LOCK_ZONE(zone); |
| 10528 | if (zone->type == dns_zone_master) { |
| 10529 | if (inline_raw(zone)) { |
| 10530 | unsigned int soacount; |
| 10531 | secure = zone->secure; |
| 10532 | INSIST(secure != zone); |
| 10533 | TRYLOCK_ZONE(result, secure); |
| 10534 | if (result != ISC_R_SUCCESS) { |
| 10535 | UNLOCK_ZONE(zone); |
| 10536 | secure = NULL; |
| 10537 | isc_thread_yield(); |
| 10538 | goto again; |
| 10539 | } |
| 10540 | |
| 10541 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 10542 | if (zone->db != NULL) { |
| 10543 | result = zone_get_from_db(zone, zone->db, NULL, |
| 10544 | &soacount, &serial, |
| 10545 | NULL, NULL, NULL, |
| 10546 | NULL, NULL); |
| 10547 | } else |
| 10548 | result = DNS_R_NOTLOADED; |
| 10549 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 10550 | if (result == ISC_R_SUCCESS && soacount > 0U) |
| 10551 | zone_send_secureserial(zone, serial); |
| 10552 | } |
| 10553 | |
| 10554 | /* XXXMPA make separate call back */ |
| 10555 | if (result == ISC_R_SUCCESS) |
| 10556 | set_resigntime(zone); |
| 10557 | } |
| 10558 | if (secure != NULL) |
| 10559 | UNLOCK_ZONE(secure); |
| 10560 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 10561 | UNLOCK_ZONE(zone); |
| 10562 | } |
| 10563 | |
| 10564 | void |
| 10565 | dns_zone_expire(dns_zone_t *zone) { |
| 10566 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10567 | |
| 10568 | LOCK_ZONE(zone); |
| 10569 | zone_expire(zone); |
| 10570 | UNLOCK_ZONE(zone); |
| 10571 | } |
| 10572 | |
| 10573 | static void |
| 10574 | zone_expire(dns_zone_t *zone) { |
| 10575 | /* |
| 10576 | * 'zone' locked by caller. |
| 10577 | */ |
| 10578 | |
| 10579 | REQUIRE(LOCKED_ZONE(zone)); |
| 10580 | |
| 10581 | dns_zone_log(zone, ISC_LOG_WARNING, "expired" ); |
| 10582 | |
| 10583 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXPIRED); |
| 10584 | zone->refresh = DNS_ZONE_DEFAULTREFRESH; |
| 10585 | zone->retry = DNS_ZONE_DEFAULTRETRY; |
| 10586 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS); |
| 10587 | zone_unload(zone); |
| 10588 | } |
| 10589 | |
| 10590 | void |
| 10591 | dns_zone_refresh(dns_zone_t *zone) { |
| 10592 | isc_interval_t i; |
| 10593 | uint32_t oldflags; |
| 10594 | unsigned int j; |
| 10595 | isc_result_t result; |
| 10596 | |
| 10597 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10598 | |
| 10599 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) |
| 10600 | return; |
| 10601 | |
| 10602 | /* |
| 10603 | * Set DNS_ZONEFLG_REFRESH so that there is only one refresh operation |
| 10604 | * in progress at a time. |
| 10605 | */ |
| 10606 | |
| 10607 | LOCK_ZONE(zone); |
| 10608 | oldflags = zone->flags; |
| 10609 | if (zone->masterscnt == 0) { |
| 10610 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOMASTERS); |
| 10611 | if ((oldflags & DNS_ZONEFLG_NOMASTERS) == 0) |
| 10612 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 10613 | "cannot refresh: no masters" ); |
| 10614 | goto unlock; |
| 10615 | } |
| 10616 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 10617 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 10618 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); |
| 10619 | if ((oldflags & (DNS_ZONEFLG_REFRESH|DNS_ZONEFLG_LOADING)) != 0) |
| 10620 | goto unlock; |
| 10621 | |
| 10622 | /* |
| 10623 | * Set the next refresh time as if refresh check has failed. |
| 10624 | * Setting this to the retry time will do that. XXXMLG |
| 10625 | * If we are successful it will be reset using zone->refresh. |
| 10626 | */ |
| 10627 | isc_interval_set(&i, zone->retry - isc_random_uniform(zone->retry / 4), |
| 10628 | 0); |
| 10629 | result = isc_time_nowplusinterval(&zone->refreshtime, &i); |
| 10630 | if (result != ISC_R_SUCCESS) |
| 10631 | dns_zone_log(zone, ISC_LOG_WARNING, |
| 10632 | "isc_time_nowplusinterval() failed: %s" , |
| 10633 | dns_result_totext(result)); |
| 10634 | |
| 10635 | /* |
| 10636 | * When lacking user-specified timer values from the SOA, |
| 10637 | * do exponential backoff of the retry time up to a |
| 10638 | * maximum of six hours. |
| 10639 | */ |
| 10640 | if (! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HAVETIMERS)) |
| 10641 | zone->retry = ISC_MIN(zone->retry * 2, 6 * 3600); |
| 10642 | |
| 10643 | zone->curmaster = 0; |
| 10644 | for (j = 0; j < zone->masterscnt; j++) |
| 10645 | zone->mastersok[j] = false; |
| 10646 | /* initiate soa query */ |
| 10647 | queue_soa_query(zone); |
| 10648 | unlock: |
| 10649 | UNLOCK_ZONE(zone); |
| 10650 | } |
| 10651 | |
| 10652 | static void |
| 10653 | zone_journal_compact(dns_zone_t *zone, dns_db_t *db, uint32_t serial) { |
| 10654 | isc_result_t result; |
| 10655 | int32_t journalsize; |
| 10656 | dns_dbversion_t *ver = NULL; |
| 10657 | uint64_t dbsize; |
| 10658 | |
| 10659 | INSIST(LOCKED_ZONE(zone)); |
| 10660 | if (inline_raw(zone)) |
| 10661 | INSIST(LOCKED_ZONE(zone->secure)); |
| 10662 | |
| 10663 | journalsize = zone->journalsize; |
| 10664 | if (journalsize == -1) { |
| 10665 | journalsize = DNS_JOURNAL_SIZE_MAX; |
| 10666 | dns_db_currentversion(db, &ver); |
| 10667 | result = dns_db_getsize(db, ver, NULL, &dbsize); |
| 10668 | dns_db_closeversion(db, &ver, false); |
| 10669 | if (result != ISC_R_SUCCESS) { |
| 10670 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 10671 | "zone_journal_compact: " |
| 10672 | "could not get zone size: %s" , |
| 10673 | isc_result_totext(result)); |
| 10674 | } else if (dbsize < DNS_JOURNAL_SIZE_MAX / 2) { |
| 10675 | journalsize = (int32_t)dbsize * 2; |
| 10676 | } |
| 10677 | } |
| 10678 | zone_debuglog(zone, "zone_journal_compact" , 1, |
| 10679 | "target journal size %d" , journalsize); |
| 10680 | result = dns_journal_compact(zone->mctx, zone->journal, |
| 10681 | serial, journalsize); |
| 10682 | switch (result) { |
| 10683 | case ISC_R_SUCCESS: |
| 10684 | case ISC_R_NOSPACE: |
| 10685 | case ISC_R_NOTFOUND: |
| 10686 | dns_zone_log(zone, ISC_LOG_DEBUG(3), |
| 10687 | "dns_journal_compact: %s" , |
| 10688 | dns_result_totext(result)); |
| 10689 | break; |
| 10690 | default: |
| 10691 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 10692 | "dns_journal_compact failed: %s" , |
| 10693 | dns_result_totext(result)); |
| 10694 | break; |
| 10695 | } |
| 10696 | } |
| 10697 | |
| 10698 | isc_result_t |
| 10699 | dns_zone_flush(dns_zone_t *zone) { |
| 10700 | isc_result_t result = ISC_R_SUCCESS; |
| 10701 | bool dumping; |
| 10702 | |
| 10703 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10704 | |
| 10705 | LOCK_ZONE(zone); |
| 10706 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FLUSH); |
| 10707 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && |
| 10708 | zone->masterfile != NULL) { |
| 10709 | result = ISC_R_ALREADYRUNNING; |
| 10710 | dumping = was_dumping(zone); |
| 10711 | } else |
| 10712 | dumping = true; |
| 10713 | UNLOCK_ZONE(zone); |
| 10714 | if (!dumping) |
| 10715 | result = zone_dump(zone, true); /* Unknown task. */ |
| 10716 | return (result); |
| 10717 | } |
| 10718 | |
| 10719 | isc_result_t |
| 10720 | dns_zone_dump(dns_zone_t *zone) { |
| 10721 | isc_result_t result = ISC_R_ALREADYRUNNING; |
| 10722 | bool dumping; |
| 10723 | |
| 10724 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10725 | |
| 10726 | LOCK_ZONE(zone); |
| 10727 | dumping = was_dumping(zone); |
| 10728 | UNLOCK_ZONE(zone); |
| 10729 | if (!dumping) |
| 10730 | result = zone_dump(zone, false); /* Unknown task. */ |
| 10731 | return (result); |
| 10732 | } |
| 10733 | |
| 10734 | static void |
| 10735 | zone_needdump(dns_zone_t *zone, unsigned int delay) { |
| 10736 | const char me[] = "zone_needdump" ; |
| 10737 | isc_time_t dumptime; |
| 10738 | isc_time_t now; |
| 10739 | |
| 10740 | /* |
| 10741 | * 'zone' locked by caller |
| 10742 | */ |
| 10743 | |
| 10744 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10745 | REQUIRE(LOCKED_ZONE(zone)); |
| 10746 | ENTER; |
| 10747 | |
| 10748 | /* |
| 10749 | * Do we have a place to dump to and are we loaded? |
| 10750 | */ |
| 10751 | if (zone->masterfile == NULL || |
| 10752 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) == 0) |
| 10753 | return; |
| 10754 | |
| 10755 | TIME_NOW(&now); |
| 10756 | /* add some noise */ |
| 10757 | DNS_ZONE_JITTER_ADD(&now, delay, &dumptime); |
| 10758 | |
| 10759 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDDUMP); |
| 10760 | if (isc_time_isepoch(&zone->dumptime) || |
| 10761 | isc_time_compare(&zone->dumptime, &dumptime) > 0) |
| 10762 | zone->dumptime = dumptime; |
| 10763 | if (zone->task != NULL) |
| 10764 | zone_settimer(zone, &now); |
| 10765 | } |
| 10766 | |
| 10767 | static void |
| 10768 | dump_done(void *arg, isc_result_t result) { |
| 10769 | const char me[] = "dump_done" ; |
| 10770 | dns_zone_t *zone = arg; |
| 10771 | dns_zone_t *secure = NULL; |
| 10772 | dns_db_t *db; |
| 10773 | dns_dbversion_t *version; |
| 10774 | bool again = false; |
| 10775 | bool compact = false; |
| 10776 | uint32_t serial; |
| 10777 | isc_result_t tresult; |
| 10778 | |
| 10779 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10780 | |
| 10781 | ENTER; |
| 10782 | |
| 10783 | if (result == ISC_R_SUCCESS && zone->journal != NULL) { |
| 10784 | /* |
| 10785 | * We don't own these, zone->dctx must stay valid. |
| 10786 | */ |
| 10787 | db = dns_dumpctx_db(zone->dctx); |
| 10788 | version = dns_dumpctx_version(zone->dctx); |
| 10789 | tresult = dns_db_getsoaserial(db, version, &serial); |
| 10790 | |
| 10791 | /* |
| 10792 | * Handle lock order inversion. |
| 10793 | */ |
| 10794 | again: |
| 10795 | LOCK_ZONE(zone); |
| 10796 | if (inline_raw(zone)) { |
| 10797 | secure = zone->secure; |
| 10798 | INSIST(secure != zone); |
| 10799 | TRYLOCK_ZONE(result, secure); |
| 10800 | if (result != ISC_R_SUCCESS) { |
| 10801 | UNLOCK_ZONE(zone); |
| 10802 | secure = NULL; |
| 10803 | isc_thread_yield(); |
| 10804 | goto again; |
| 10805 | } |
| 10806 | } |
| 10807 | |
| 10808 | /* |
| 10809 | * If there is a secure version of this zone |
| 10810 | * use its serial if it is less than ours. |
| 10811 | */ |
| 10812 | if (tresult == ISC_R_SUCCESS && secure != NULL) { |
| 10813 | uint32_t sserial; |
| 10814 | isc_result_t mresult; |
| 10815 | |
| 10816 | ZONEDB_LOCK(&secure->dblock, isc_rwlocktype_read); |
| 10817 | if (secure->db != NULL) { |
| 10818 | mresult = dns_db_getsoaserial(zone->secure->db, |
| 10819 | NULL, &sserial); |
| 10820 | if (mresult == ISC_R_SUCCESS && |
| 10821 | isc_serial_lt(sserial, serial)) |
| 10822 | serial = sserial; |
| 10823 | } |
| 10824 | ZONEDB_UNLOCK(&secure->dblock, isc_rwlocktype_read); |
| 10825 | } |
| 10826 | if (tresult == ISC_R_SUCCESS && zone->xfr == NULL) { |
| 10827 | dns_db_t *zdb = NULL; |
| 10828 | if (dns_zone_getdb(zone, &zdb) == ISC_R_SUCCESS) { |
| 10829 | zone_journal_compact(zone, zdb, serial); |
| 10830 | dns_db_detach(&zdb); |
| 10831 | } |
| 10832 | } else if (tresult == ISC_R_SUCCESS) { |
| 10833 | compact = true; |
| 10834 | zone->compact_serial = serial; |
| 10835 | } |
| 10836 | if (secure != NULL) |
| 10837 | UNLOCK_ZONE(secure); |
| 10838 | UNLOCK_ZONE(zone); |
| 10839 | } |
| 10840 | |
| 10841 | LOCK_ZONE(zone); |
| 10842 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DUMPING); |
| 10843 | if (compact) |
| 10844 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT); |
| 10845 | if (result != ISC_R_SUCCESS && result != ISC_R_CANCELED) { |
| 10846 | /* |
| 10847 | * Try again in a short while. |
| 10848 | */ |
| 10849 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 10850 | } else if (result == ISC_R_SUCCESS && |
| 10851 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) && |
| 10852 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && |
| 10853 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { |
| 10854 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); |
| 10855 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING); |
| 10856 | isc_time_settoepoch(&zone->dumptime); |
| 10857 | again = true; |
| 10858 | } else if (result == ISC_R_SUCCESS) |
| 10859 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FLUSH); |
| 10860 | |
| 10861 | if (zone->dctx != NULL) |
| 10862 | dns_dumpctx_detach(&zone->dctx); |
| 10863 | zonemgr_putio(&zone->writeio); |
| 10864 | UNLOCK_ZONE(zone); |
| 10865 | if (again) |
| 10866 | (void)zone_dump(zone, false); |
| 10867 | dns_zone_idetach(&zone); |
| 10868 | } |
| 10869 | |
| 10870 | static isc_result_t |
| 10871 | zone_dump(dns_zone_t *zone, bool compact) { |
| 10872 | const char me[] = "zone_dump" ; |
| 10873 | isc_result_t result; |
| 10874 | dns_dbversion_t *version = NULL; |
| 10875 | bool again; |
| 10876 | dns_db_t *db = NULL; |
| 10877 | char *masterfile = NULL; |
| 10878 | dns_masterformat_t masterformat = dns_masterformat_none; |
| 10879 | |
| 10880 | /* |
| 10881 | * 'compact' MUST only be set if we are task locked. |
| 10882 | */ |
| 10883 | |
| 10884 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10885 | ENTER; |
| 10886 | |
| 10887 | redo: |
| 10888 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 10889 | if (zone->db != NULL) |
| 10890 | dns_db_attach(zone->db, &db); |
| 10891 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 10892 | LOCK_ZONE(zone); |
| 10893 | if (zone->masterfile != NULL) { |
| 10894 | masterfile = isc_mem_strdup(zone->mctx, zone->masterfile); |
| 10895 | masterformat = zone->masterformat; |
| 10896 | } |
| 10897 | UNLOCK_ZONE(zone); |
| 10898 | if (db == NULL) { |
| 10899 | result = DNS_R_NOTLOADED; |
| 10900 | goto fail; |
| 10901 | } |
| 10902 | if (masterfile == NULL) { |
| 10903 | result = DNS_R_NOMASTERFILE; |
| 10904 | goto fail; |
| 10905 | } |
| 10906 | |
| 10907 | if (compact && zone->type != dns_zone_stub) { |
| 10908 | dns_zone_t *dummy = NULL; |
| 10909 | LOCK_ZONE(zone); |
| 10910 | zone_iattach(zone, &dummy); |
| 10911 | result = zonemgr_getio(zone->zmgr, false, zone->task, |
| 10912 | zone_gotwritehandle, zone, |
| 10913 | &zone->writeio); |
| 10914 | if (result != ISC_R_SUCCESS) |
| 10915 | zone_idetach(&dummy); |
| 10916 | else |
| 10917 | result = DNS_R_CONTINUE; |
| 10918 | UNLOCK_ZONE(zone); |
| 10919 | } else { |
| 10920 | const dns_master_style_t *output_style; |
| 10921 | |
| 10922 | dns_masterrawheader_t rawdata; |
| 10923 | dns_db_currentversion(db, &version); |
| 10924 | dns_master_initrawheader(&rawdata); |
| 10925 | if (inline_secure(zone)) |
| 10926 | get_raw_serial(zone->raw, &rawdata); |
| 10927 | if (zone->type == dns_zone_key) |
| 10928 | output_style = &dns_master_style_keyzone; |
| 10929 | else |
| 10930 | output_style = &dns_master_style_default; |
| 10931 | result = dns_master_dump(zone->mctx, db, version, |
| 10932 | output_style, masterfile, |
| 10933 | masterformat, &rawdata); |
| 10934 | dns_db_closeversion(db, &version, false); |
| 10935 | } |
| 10936 | fail: |
| 10937 | if (db != NULL) |
| 10938 | dns_db_detach(&db); |
| 10939 | if (masterfile != NULL) |
| 10940 | isc_mem_free(zone->mctx, masterfile); |
| 10941 | masterfile = NULL; |
| 10942 | |
| 10943 | if (result == DNS_R_CONTINUE) |
| 10944 | return (ISC_R_SUCCESS); /* XXXMPA */ |
| 10945 | |
| 10946 | again = false; |
| 10947 | LOCK_ZONE(zone); |
| 10948 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DUMPING); |
| 10949 | if (result != ISC_R_SUCCESS) { |
| 10950 | /* |
| 10951 | * Try again in a short while. |
| 10952 | */ |
| 10953 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 10954 | } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) && |
| 10955 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && |
| 10956 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { |
| 10957 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); |
| 10958 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING); |
| 10959 | isc_time_settoepoch(&zone->dumptime); |
| 10960 | again = true; |
| 10961 | } else |
| 10962 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FLUSH); |
| 10963 | UNLOCK_ZONE(zone); |
| 10964 | if (again) |
| 10965 | goto redo; |
| 10966 | |
| 10967 | return (result); |
| 10968 | } |
| 10969 | |
| 10970 | static isc_result_t |
| 10971 | dumptostream(dns_zone_t *zone, FILE *fd, const dns_master_style_t *style, |
| 10972 | dns_masterformat_t format, const uint32_t rawversion) |
| 10973 | { |
| 10974 | isc_result_t result; |
| 10975 | dns_dbversion_t *version = NULL; |
| 10976 | dns_db_t *db = NULL; |
| 10977 | dns_masterrawheader_t rawdata; |
| 10978 | |
| 10979 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 10980 | |
| 10981 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 10982 | if (zone->db != NULL) |
| 10983 | dns_db_attach(zone->db, &db); |
| 10984 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 10985 | if (db == NULL) |
| 10986 | return (DNS_R_NOTLOADED); |
| 10987 | |
| 10988 | dns_db_currentversion(db, &version); |
| 10989 | dns_master_initrawheader(&rawdata); |
| 10990 | if (rawversion == 0) |
| 10991 | rawdata.flags |= DNS_MASTERRAW_COMPAT; |
| 10992 | else if (inline_secure(zone)) |
| 10993 | get_raw_serial(zone->raw, &rawdata); |
| 10994 | else if (zone->sourceserialset) { |
| 10995 | rawdata.flags = DNS_MASTERRAW_SOURCESERIALSET; |
| 10996 | rawdata.sourceserial = zone->sourceserial; |
| 10997 | } |
| 10998 | result = dns_master_dumptostream(zone->mctx, db, version, style, |
| 10999 | format, &rawdata, fd); |
| 11000 | dns_db_closeversion(db, &version, false); |
| 11001 | dns_db_detach(&db); |
| 11002 | return (result); |
| 11003 | } |
| 11004 | |
| 11005 | isc_result_t |
| 11006 | dns_zone_dumptostream(dns_zone_t *zone, FILE *fd, dns_masterformat_t format, |
| 11007 | const dns_master_style_t *style, |
| 11008 | const uint32_t rawversion) |
| 11009 | { |
| 11010 | return (dumptostream(zone, fd, style, format, rawversion)); |
| 11011 | } |
| 11012 | |
| 11013 | void |
| 11014 | dns_zone_unload(dns_zone_t *zone) { |
| 11015 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11016 | |
| 11017 | LOCK_ZONE(zone); |
| 11018 | zone_unload(zone); |
| 11019 | UNLOCK_ZONE(zone); |
| 11020 | } |
| 11021 | |
| 11022 | static void |
| 11023 | notify_cancel(dns_zone_t *zone) { |
| 11024 | dns_notify_t *notify; |
| 11025 | |
| 11026 | /* |
| 11027 | * 'zone' locked by caller. |
| 11028 | */ |
| 11029 | |
| 11030 | REQUIRE(LOCKED_ZONE(zone)); |
| 11031 | |
| 11032 | for (notify = ISC_LIST_HEAD(zone->notifies); |
| 11033 | notify != NULL; |
| 11034 | notify = ISC_LIST_NEXT(notify, link)) { |
| 11035 | if (notify->find != NULL) |
| 11036 | dns_adb_cancelfind(notify->find); |
| 11037 | if (notify->request != NULL) |
| 11038 | dns_request_cancel(notify->request); |
| 11039 | } |
| 11040 | } |
| 11041 | |
| 11042 | static void |
| 11043 | forward_cancel(dns_zone_t *zone) { |
| 11044 | dns_forward_t *forward; |
| 11045 | |
| 11046 | /* |
| 11047 | * 'zone' locked by caller. |
| 11048 | */ |
| 11049 | |
| 11050 | REQUIRE(LOCKED_ZONE(zone)); |
| 11051 | |
| 11052 | for (forward = ISC_LIST_HEAD(zone->forwards); |
| 11053 | forward != NULL; |
| 11054 | forward = ISC_LIST_NEXT(forward, link)) { |
| 11055 | if (forward->request != NULL) |
| 11056 | dns_request_cancel(forward->request); |
| 11057 | } |
| 11058 | } |
| 11059 | |
| 11060 | static void |
| 11061 | zone_unload(dns_zone_t *zone) { |
| 11062 | /* |
| 11063 | * 'zone' locked by caller. |
| 11064 | */ |
| 11065 | |
| 11066 | REQUIRE(LOCKED_ZONE(zone)); |
| 11067 | |
| 11068 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) || |
| 11069 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { |
| 11070 | if (zone->writeio != NULL) |
| 11071 | zonemgr_cancelio(zone->writeio); |
| 11072 | |
| 11073 | if (zone->dctx != NULL) |
| 11074 | dns_dumpctx_cancel(zone->dctx); |
| 11075 | } |
| 11076 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); |
| 11077 | zone_detachdb(zone); |
| 11078 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
| 11079 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADED); |
| 11080 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); |
| 11081 | |
| 11082 | if (zone->type == dns_zone_mirror) { |
| 11083 | dns_zone_log(zone, ISC_LOG_INFO, |
| 11084 | "mirror zone is no longer in use; " |
| 11085 | "reverting to normal recursion" ); |
| 11086 | } |
| 11087 | } |
| 11088 | |
| 11089 | void |
| 11090 | dns_zone_setminrefreshtime(dns_zone_t *zone, uint32_t val) { |
| 11091 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11092 | REQUIRE(val > 0); |
| 11093 | |
| 11094 | zone->minrefresh = val; |
| 11095 | } |
| 11096 | |
| 11097 | void |
| 11098 | dns_zone_setmaxrefreshtime(dns_zone_t *zone, uint32_t val) { |
| 11099 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11100 | REQUIRE(val > 0); |
| 11101 | |
| 11102 | zone->maxrefresh = val; |
| 11103 | } |
| 11104 | |
| 11105 | void |
| 11106 | dns_zone_setminretrytime(dns_zone_t *zone, uint32_t val) { |
| 11107 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11108 | REQUIRE(val > 0); |
| 11109 | |
| 11110 | zone->minretry = val; |
| 11111 | } |
| 11112 | |
| 11113 | void |
| 11114 | dns_zone_setmaxretrytime(dns_zone_t *zone, uint32_t val) { |
| 11115 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11116 | REQUIRE(val > 0); |
| 11117 | |
| 11118 | zone->maxretry = val; |
| 11119 | } |
| 11120 | |
| 11121 | uint32_t |
| 11122 | dns_zone_getmaxrecords(dns_zone_t *zone) { |
| 11123 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11124 | |
| 11125 | return (zone->maxrecords); |
| 11126 | } |
| 11127 | |
| 11128 | void |
| 11129 | dns_zone_setmaxrecords(dns_zone_t *zone, uint32_t val) { |
| 11130 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11131 | |
| 11132 | zone->maxrecords = val; |
| 11133 | } |
| 11134 | |
| 11135 | static bool |
| 11136 | notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name, |
| 11137 | isc_sockaddr_t *addr, dns_tsigkey_t *key) |
| 11138 | { |
| 11139 | dns_notify_t *notify; |
| 11140 | dns_zonemgr_t *zmgr; |
| 11141 | isc_result_t result; |
| 11142 | |
| 11143 | for (notify = ISC_LIST_HEAD(zone->notifies); |
| 11144 | notify != NULL; |
| 11145 | notify = ISC_LIST_NEXT(notify, link)) { |
| 11146 | if (notify->request != NULL) |
| 11147 | continue; |
| 11148 | if (name != NULL && dns_name_dynamic(¬ify->ns) && |
| 11149 | dns_name_equal(name, ¬ify->ns)) |
| 11150 | goto requeue; |
| 11151 | if (addr != NULL && isc_sockaddr_equal(addr, ¬ify->dst) && |
| 11152 | notify->key == key) |
| 11153 | goto requeue; |
| 11154 | } |
| 11155 | return (false); |
| 11156 | |
| 11157 | requeue: |
| 11158 | /* |
| 11159 | * If we are enqueued on the startup ratelimiter and this is |
| 11160 | * not a startup notify, re-enqueue on the normal notify |
| 11161 | * ratelimiter. |
| 11162 | */ |
| 11163 | if (notify->event != NULL && (flags & DNS_NOTIFY_STARTUP) == 0 && |
| 11164 | (notify->flags & DNS_NOTIFY_STARTUP) != 0) { |
| 11165 | zmgr = notify->zone->zmgr; |
| 11166 | result = isc_ratelimiter_dequeue(zmgr->startupnotifyrl, |
| 11167 | notify->event); |
| 11168 | if (result != ISC_R_SUCCESS) |
| 11169 | return (true); |
| 11170 | |
| 11171 | notify->flags &= ~DNS_NOTIFY_STARTUP; |
| 11172 | result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl, |
| 11173 | notify->zone->task, |
| 11174 | ¬ify->event); |
| 11175 | if (result != ISC_R_SUCCESS) { |
| 11176 | isc_event_free(¬ify->event); |
| 11177 | return (false); |
| 11178 | } |
| 11179 | } |
| 11180 | |
| 11181 | return (true); |
| 11182 | } |
| 11183 | |
| 11184 | static bool |
| 11185 | notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) { |
| 11186 | dns_tsigkey_t *key = NULL; |
| 11187 | isc_sockaddr_t src; |
| 11188 | isc_sockaddr_t any; |
| 11189 | bool isself; |
| 11190 | isc_netaddr_t dstaddr; |
| 11191 | isc_result_t result; |
| 11192 | |
| 11193 | if (zone->view == NULL || zone->isself == NULL) |
| 11194 | return (false); |
| 11195 | |
| 11196 | switch (isc_sockaddr_pf(dst)) { |
| 11197 | case PF_INET: |
| 11198 | src = zone->notifysrc4; |
| 11199 | isc_sockaddr_any(&any); |
| 11200 | break; |
| 11201 | case PF_INET6: |
| 11202 | src = zone->notifysrc6; |
| 11203 | isc_sockaddr_any6(&any); |
| 11204 | break; |
| 11205 | default: |
| 11206 | return (false); |
| 11207 | } |
| 11208 | |
| 11209 | /* |
| 11210 | * When sending from any the kernel will assign a source address |
| 11211 | * that matches the destination address. |
| 11212 | */ |
| 11213 | if (isc_sockaddr_eqaddr(&any, &src)) |
| 11214 | src = *dst; |
| 11215 | |
| 11216 | isc_netaddr_fromsockaddr(&dstaddr, dst); |
| 11217 | result = dns_view_getpeertsig(zone->view, &dstaddr, &key); |
| 11218 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) |
| 11219 | return (false); |
| 11220 | isself = (zone->isself)(zone->view, key, &src, dst, zone->rdclass, |
| 11221 | zone->isselfarg); |
| 11222 | if (key != NULL) |
| 11223 | dns_tsigkey_detach(&key); |
| 11224 | return (isself); |
| 11225 | } |
| 11226 | |
| 11227 | static void |
| 11228 | notify_destroy(dns_notify_t *notify, bool locked) { |
| 11229 | isc_mem_t *mctx; |
| 11230 | |
| 11231 | REQUIRE(DNS_NOTIFY_VALID(notify)); |
| 11232 | |
| 11233 | if (notify->zone != NULL) { |
| 11234 | if (!locked) |
| 11235 | LOCK_ZONE(notify->zone); |
| 11236 | REQUIRE(LOCKED_ZONE(notify->zone)); |
| 11237 | if (ISC_LINK_LINKED(notify, link)) |
| 11238 | ISC_LIST_UNLINK(notify->zone->notifies, notify, link); |
| 11239 | if (!locked) |
| 11240 | UNLOCK_ZONE(notify->zone); |
| 11241 | if (locked) |
| 11242 | zone_idetach(¬ify->zone); |
| 11243 | else |
| 11244 | dns_zone_idetach(¬ify->zone); |
| 11245 | } |
| 11246 | if (notify->find != NULL) |
| 11247 | dns_adb_destroyfind(¬ify->find); |
| 11248 | if (notify->request != NULL) |
| 11249 | dns_request_destroy(¬ify->request); |
| 11250 | if (dns_name_dynamic(¬ify->ns)) |
| 11251 | dns_name_free(¬ify->ns, notify->mctx); |
| 11252 | if (notify->key != NULL) |
| 11253 | dns_tsigkey_detach(¬ify->key); |
| 11254 | mctx = notify->mctx; |
| 11255 | isc_mem_put(notify->mctx, notify, sizeof(*notify)); |
| 11256 | isc_mem_detach(&mctx); |
| 11257 | } |
| 11258 | |
| 11259 | static isc_result_t |
| 11260 | notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) { |
| 11261 | dns_notify_t *notify; |
| 11262 | |
| 11263 | REQUIRE(notifyp != NULL && *notifyp == NULL); |
| 11264 | |
| 11265 | notify = isc_mem_get(mctx, sizeof(*notify)); |
| 11266 | if (notify == NULL) |
| 11267 | return (ISC_R_NOMEMORY); |
| 11268 | |
| 11269 | notify->mctx = NULL; |
| 11270 | isc_mem_attach(mctx, ¬ify->mctx); |
| 11271 | notify->flags = flags; |
| 11272 | notify->zone = NULL; |
| 11273 | notify->find = NULL; |
| 11274 | notify->request = NULL; |
| 11275 | notify->key = NULL; |
| 11276 | notify->event = NULL; |
| 11277 | isc_sockaddr_any(¬ify->dst); |
| 11278 | dns_name_init(¬ify->ns, NULL); |
| 11279 | ISC_LINK_INIT(notify, link); |
| 11280 | notify->magic = NOTIFY_MAGIC; |
| 11281 | *notifyp = notify; |
| 11282 | return (ISC_R_SUCCESS); |
| 11283 | } |
| 11284 | |
| 11285 | /* |
| 11286 | * XXXAG should check for DNS_ZONEFLG_EXITING |
| 11287 | */ |
| 11288 | static void |
| 11289 | process_adb_event(isc_task_t *task, isc_event_t *ev) { |
| 11290 | dns_notify_t *notify; |
| 11291 | isc_eventtype_t result; |
| 11292 | |
| 11293 | UNUSED(task); |
| 11294 | |
| 11295 | notify = ev->ev_arg; |
| 11296 | REQUIRE(DNS_NOTIFY_VALID(notify)); |
| 11297 | INSIST(task == notify->zone->task); |
| 11298 | result = ev->ev_type; |
| 11299 | isc_event_free(&ev); |
| 11300 | if (result == DNS_EVENT_ADBMOREADDRESSES) { |
| 11301 | dns_adb_destroyfind(¬ify->find); |
| 11302 | notify_find_address(notify); |
| 11303 | return; |
| 11304 | } |
| 11305 | if (result == DNS_EVENT_ADBNOMOREADDRESSES) { |
| 11306 | LOCK_ZONE(notify->zone); |
| 11307 | notify_send(notify); |
| 11308 | UNLOCK_ZONE(notify->zone); |
| 11309 | } |
| 11310 | notify_destroy(notify, false); |
| 11311 | } |
| 11312 | |
| 11313 | static void |
| 11314 | notify_find_address(dns_notify_t *notify) { |
| 11315 | isc_result_t result; |
| 11316 | unsigned int options; |
| 11317 | |
| 11318 | REQUIRE(DNS_NOTIFY_VALID(notify)); |
| 11319 | options = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_INET | |
| 11320 | DNS_ADBFIND_INET6 | DNS_ADBFIND_RETURNLAME; |
| 11321 | |
| 11322 | if (notify->zone->view->adb == NULL) |
| 11323 | goto destroy; |
| 11324 | |
| 11325 | result = dns_adb_createfind(notify->zone->view->adb, |
| 11326 | notify->zone->task, |
| 11327 | process_adb_event, notify, |
| 11328 | ¬ify->ns, dns_rootname, 0, |
| 11329 | options, 0, NULL, |
| 11330 | notify->zone->view->dstport, |
| 11331 | 0, NULL, ¬ify->find); |
| 11332 | |
| 11333 | /* Something failed? */ |
| 11334 | if (result != ISC_R_SUCCESS) |
| 11335 | goto destroy; |
| 11336 | |
| 11337 | /* More addresses pending? */ |
| 11338 | if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0) |
| 11339 | return; |
| 11340 | |
| 11341 | /* We have as many addresses as we can get. */ |
| 11342 | LOCK_ZONE(notify->zone); |
| 11343 | notify_send(notify); |
| 11344 | UNLOCK_ZONE(notify->zone); |
| 11345 | |
| 11346 | destroy: |
| 11347 | notify_destroy(notify, false); |
| 11348 | } |
| 11349 | |
| 11350 | |
| 11351 | static isc_result_t |
| 11352 | notify_send_queue(dns_notify_t *notify, bool startup) { |
| 11353 | isc_event_t *e; |
| 11354 | isc_result_t result; |
| 11355 | |
| 11356 | INSIST(notify->event == NULL); |
| 11357 | e = isc_event_allocate(notify->mctx, NULL, DNS_EVENT_NOTIFYSENDTOADDR, |
| 11358 | notify_send_toaddr, notify, sizeof(isc_event_t)); |
| 11359 | if (e == NULL) |
| 11360 | return (ISC_R_NOMEMORY); |
| 11361 | if (startup) |
| 11362 | notify->event = e; |
| 11363 | e->ev_arg = notify; |
| 11364 | e->ev_sender = NULL; |
| 11365 | result = isc_ratelimiter_enqueue(startup |
| 11366 | ? notify->zone->zmgr->startupnotifyrl |
| 11367 | : notify->zone->zmgr->notifyrl, |
| 11368 | notify->zone->task, &e); |
| 11369 | if (result != ISC_R_SUCCESS) { |
| 11370 | isc_event_free(&e); |
| 11371 | notify->event = NULL; |
| 11372 | } |
| 11373 | return (result); |
| 11374 | } |
| 11375 | |
| 11376 | static void |
| 11377 | notify_send_toaddr(isc_task_t *task, isc_event_t *event) { |
| 11378 | dns_notify_t *notify; |
| 11379 | isc_result_t result; |
| 11380 | dns_message_t *message = NULL; |
| 11381 | isc_netaddr_t dstip; |
| 11382 | dns_tsigkey_t *key = NULL; |
| 11383 | char addrbuf[ISC_SOCKADDR_FORMATSIZE]; |
| 11384 | isc_sockaddr_t src; |
| 11385 | unsigned int options, timeout; |
| 11386 | bool have_notifysource = false; |
| 11387 | bool have_notifydscp = false; |
| 11388 | isc_dscp_t dscp = -1; |
| 11389 | |
| 11390 | notify = event->ev_arg; |
| 11391 | REQUIRE(DNS_NOTIFY_VALID(notify)); |
| 11392 | |
| 11393 | UNUSED(task); |
| 11394 | |
| 11395 | LOCK_ZONE(notify->zone); |
| 11396 | |
| 11397 | notify->event = NULL; |
| 11398 | |
| 11399 | if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0) { |
| 11400 | result = ISC_R_CANCELED; |
| 11401 | goto cleanup; |
| 11402 | } |
| 11403 | |
| 11404 | if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 || |
| 11405 | DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING) || |
| 11406 | notify->zone->view->requestmgr == NULL || |
| 11407 | notify->zone->db == NULL) { |
| 11408 | result = ISC_R_CANCELED; |
| 11409 | goto cleanup; |
| 11410 | } |
| 11411 | |
| 11412 | /* |
| 11413 | * The raw IPv4 address should also exist. Don't send to the |
| 11414 | * mapped form. |
| 11415 | */ |
| 11416 | if (isc_sockaddr_pf(¬ify->dst) == PF_INET6 && |
| 11417 | IN6_IS_ADDR_V4MAPPED(¬ify->dst.type.sin6.sin6_addr)) { |
| 11418 | isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); |
| 11419 | notify_log(notify->zone, ISC_LOG_DEBUG(3), |
| 11420 | "notify: ignoring IPv6 mapped IPV4 address: %s" , |
| 11421 | addrbuf); |
| 11422 | result = ISC_R_CANCELED; |
| 11423 | goto cleanup; |
| 11424 | } |
| 11425 | |
| 11426 | result = notify_createmessage(notify->zone, notify->flags, &message); |
| 11427 | if (result != ISC_R_SUCCESS) |
| 11428 | goto cleanup; |
| 11429 | |
| 11430 | isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); |
| 11431 | if (notify->key != NULL) { |
| 11432 | /* Transfer ownership of key */ |
| 11433 | key = notify->key; |
| 11434 | notify->key = NULL; |
| 11435 | } else { |
| 11436 | isc_netaddr_fromsockaddr(&dstip, ¬ify->dst); |
| 11437 | result = dns_view_getpeertsig(notify->zone->view, &dstip, &key); |
| 11438 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { |
| 11439 | notify_log(notify->zone, ISC_LOG_ERROR, |
| 11440 | "NOTIFY to %s not sent. " |
| 11441 | "Peer TSIG key lookup failure." , addrbuf); |
| 11442 | goto cleanup_message; |
| 11443 | } |
| 11444 | } |
| 11445 | |
| 11446 | /* XXX: should we log the tsig key too? */ |
| 11447 | notify_log(notify->zone, ISC_LOG_DEBUG(3), "sending notify to %s" , |
| 11448 | addrbuf); |
| 11449 | options = 0; |
| 11450 | if (notify->zone->view->peers != NULL) { |
| 11451 | dns_peer_t *peer = NULL; |
| 11452 | bool usetcp = false; |
| 11453 | result = dns_peerlist_peerbyaddr(notify->zone->view->peers, |
| 11454 | &dstip, &peer); |
| 11455 | if (result == ISC_R_SUCCESS) { |
| 11456 | result = dns_peer_getnotifysource(peer, &src); |
| 11457 | if (result == ISC_R_SUCCESS) |
| 11458 | have_notifysource = true; |
| 11459 | dns_peer_getnotifydscp(peer, &dscp); |
| 11460 | if (dscp != -1) |
| 11461 | have_notifydscp = true; |
| 11462 | result = dns_peer_getforcetcp(peer, &usetcp); |
| 11463 | if (result == ISC_R_SUCCESS && usetcp) |
| 11464 | options |= DNS_FETCHOPT_TCP; |
| 11465 | } |
| 11466 | } |
| 11467 | switch (isc_sockaddr_pf(¬ify->dst)) { |
| 11468 | case PF_INET: |
| 11469 | if (!have_notifysource) |
| 11470 | src = notify->zone->notifysrc4; |
| 11471 | if (!have_notifydscp) |
| 11472 | dscp = notify->zone->notifysrc4dscp; |
| 11473 | break; |
| 11474 | case PF_INET6: |
| 11475 | if (!have_notifysource) |
| 11476 | src = notify->zone->notifysrc6; |
| 11477 | if (!have_notifydscp) |
| 11478 | dscp = notify->zone->notifysrc6dscp; |
| 11479 | break; |
| 11480 | default: |
| 11481 | result = ISC_R_NOTIMPLEMENTED; |
| 11482 | goto cleanup_key; |
| 11483 | } |
| 11484 | timeout = 15; |
| 11485 | if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_DIALNOTIFY)) |
| 11486 | timeout = 30; |
| 11487 | result = dns_request_createvia(notify->zone->view->requestmgr, |
| 11488 | message, &src, ¬ify->dst, dscp, |
| 11489 | options, key, timeout * 3, timeout, |
| 11490 | 0, notify->zone->task, notify_done, |
| 11491 | notify, ¬ify->request); |
| 11492 | if (result == ISC_R_SUCCESS) { |
| 11493 | if (isc_sockaddr_pf(¬ify->dst) == AF_INET) { |
| 11494 | inc_stats(notify->zone, |
| 11495 | dns_zonestatscounter_notifyoutv4); |
| 11496 | } else { |
| 11497 | inc_stats(notify->zone, |
| 11498 | dns_zonestatscounter_notifyoutv6); |
| 11499 | } |
| 11500 | } |
| 11501 | |
| 11502 | cleanup_key: |
| 11503 | if (key != NULL) |
| 11504 | dns_tsigkey_detach(&key); |
| 11505 | cleanup_message: |
| 11506 | dns_message_destroy(&message); |
| 11507 | cleanup: |
| 11508 | UNLOCK_ZONE(notify->zone); |
| 11509 | isc_event_free(&event); |
| 11510 | if (result != ISC_R_SUCCESS) |
| 11511 | notify_destroy(notify, false); |
| 11512 | } |
| 11513 | |
| 11514 | static void |
| 11515 | notify_send(dns_notify_t *notify) { |
| 11516 | dns_adbaddrinfo_t *ai; |
| 11517 | isc_sockaddr_t dst; |
| 11518 | isc_result_t result; |
| 11519 | dns_notify_t *newnotify = NULL; |
| 11520 | unsigned int flags; |
| 11521 | bool startup; |
| 11522 | |
| 11523 | /* |
| 11524 | * Zone lock held by caller. |
| 11525 | */ |
| 11526 | REQUIRE(DNS_NOTIFY_VALID(notify)); |
| 11527 | REQUIRE(LOCKED_ZONE(notify->zone)); |
| 11528 | |
| 11529 | if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING)) |
| 11530 | return; |
| 11531 | |
| 11532 | for (ai = ISC_LIST_HEAD(notify->find->list); |
| 11533 | ai != NULL; |
| 11534 | ai = ISC_LIST_NEXT(ai, publink)) { |
| 11535 | dst = ai->sockaddr; |
| 11536 | if (notify_isqueued(notify->zone, notify->flags, NULL, &dst, |
| 11537 | NULL)) |
| 11538 | continue; |
| 11539 | if (notify_isself(notify->zone, &dst)) |
| 11540 | continue; |
| 11541 | newnotify = NULL; |
| 11542 | flags = notify->flags & DNS_NOTIFY_NOSOA; |
| 11543 | result = notify_create(notify->mctx, flags, &newnotify); |
| 11544 | if (result != ISC_R_SUCCESS) |
| 11545 | goto cleanup; |
| 11546 | zone_iattach(notify->zone, &newnotify->zone); |
| 11547 | ISC_LIST_APPEND(newnotify->zone->notifies, newnotify, link); |
| 11548 | newnotify->dst = dst; |
| 11549 | startup = ((notify->flags & DNS_NOTIFY_STARTUP) != 0); |
| 11550 | result = notify_send_queue(newnotify, startup); |
| 11551 | if (result != ISC_R_SUCCESS) |
| 11552 | goto cleanup; |
| 11553 | newnotify = NULL; |
| 11554 | } |
| 11555 | |
| 11556 | cleanup: |
| 11557 | if (newnotify != NULL) |
| 11558 | notify_destroy(newnotify, true); |
| 11559 | } |
| 11560 | |
| 11561 | void |
| 11562 | dns_zone_notify(dns_zone_t *zone) { |
| 11563 | isc_time_t now; |
| 11564 | |
| 11565 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11566 | |
| 11567 | LOCK_ZONE(zone); |
| 11568 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 11569 | |
| 11570 | TIME_NOW(&now); |
| 11571 | zone_settimer(zone, &now); |
| 11572 | UNLOCK_ZONE(zone); |
| 11573 | } |
| 11574 | |
| 11575 | static void |
| 11576 | zone_notify(dns_zone_t *zone, isc_time_t *now) { |
| 11577 | dns_dbnode_t *node = NULL; |
| 11578 | dns_db_t *zonedb = NULL; |
| 11579 | dns_dbversion_t *version = NULL; |
| 11580 | dns_name_t *origin = NULL; |
| 11581 | dns_name_t master; |
| 11582 | dns_rdata_ns_t ns; |
| 11583 | dns_rdata_soa_t soa; |
| 11584 | uint32_t serial; |
| 11585 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 11586 | dns_rdataset_t nsrdset; |
| 11587 | dns_rdataset_t soardset; |
| 11588 | isc_result_t result; |
| 11589 | unsigned int i; |
| 11590 | isc_sockaddr_t dst; |
| 11591 | bool isqueued; |
| 11592 | dns_notifytype_t notifytype; |
| 11593 | unsigned int flags = 0; |
| 11594 | bool loggednotify = false; |
| 11595 | bool startup; |
| 11596 | |
| 11597 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 11598 | |
| 11599 | LOCK_ZONE(zone); |
| 11600 | startup = !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 11601 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 11602 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY); |
| 11603 | notifytype = zone->notifytype; |
| 11604 | DNS_ZONE_TIME_ADD(now, zone->notifydelay, &zone->notifytime); |
| 11605 | UNLOCK_ZONE(zone); |
| 11606 | |
| 11607 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || |
| 11608 | ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) |
| 11609 | return; |
| 11610 | |
| 11611 | if (notifytype == dns_notifytype_no) |
| 11612 | return; |
| 11613 | |
| 11614 | if (notifytype == dns_notifytype_masteronly && |
| 11615 | zone->type != dns_zone_master) |
| 11616 | return; |
| 11617 | |
| 11618 | origin = &zone->origin; |
| 11619 | |
| 11620 | /* |
| 11621 | * If the zone is dialup we are done as we don't want to send |
| 11622 | * the current soa so as to force a refresh query. |
| 11623 | */ |
| 11624 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY)) |
| 11625 | flags |= DNS_NOTIFY_NOSOA; |
| 11626 | |
| 11627 | /* |
| 11628 | * Record that this was a notify due to starting up. |
| 11629 | */ |
| 11630 | if (startup) |
| 11631 | flags |= DNS_NOTIFY_STARTUP; |
| 11632 | |
| 11633 | /* |
| 11634 | * Get SOA RRset. |
| 11635 | */ |
| 11636 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 11637 | if (zone->db != NULL) |
| 11638 | dns_db_attach(zone->db, &zonedb); |
| 11639 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 11640 | if (zonedb == NULL) |
| 11641 | return; |
| 11642 | dns_db_currentversion(zonedb, &version); |
| 11643 | result = dns_db_findnode(zonedb, origin, false, &node); |
| 11644 | if (result != ISC_R_SUCCESS) |
| 11645 | goto cleanup1; |
| 11646 | |
| 11647 | dns_rdataset_init(&soardset); |
| 11648 | result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_soa, |
| 11649 | dns_rdatatype_none, 0, &soardset, NULL); |
| 11650 | if (result != ISC_R_SUCCESS) |
| 11651 | goto cleanup2; |
| 11652 | |
| 11653 | /* |
| 11654 | * Find serial and master server's name. |
| 11655 | */ |
| 11656 | dns_name_init(&master, NULL); |
| 11657 | result = dns_rdataset_first(&soardset); |
| 11658 | if (result != ISC_R_SUCCESS) |
| 11659 | goto cleanup3; |
| 11660 | dns_rdataset_current(&soardset, &rdata); |
| 11661 | result = dns_rdata_tostruct(&rdata, &soa, NULL); |
| 11662 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 11663 | dns_rdata_reset(&rdata); |
| 11664 | result = dns_name_dup(&soa.origin, zone->mctx, &master); |
| 11665 | serial = soa.serial; |
| 11666 | dns_rdataset_disassociate(&soardset); |
| 11667 | if (result != ISC_R_SUCCESS) |
| 11668 | goto cleanup3; |
| 11669 | |
| 11670 | /* |
| 11671 | * Enqueue notify requests for 'also-notify' servers. |
| 11672 | */ |
| 11673 | LOCK_ZONE(zone); |
| 11674 | for (i = 0; i < zone->notifycnt; i++) { |
| 11675 | dns_tsigkey_t *key = NULL; |
| 11676 | dns_notify_t *notify = NULL; |
| 11677 | |
| 11678 | if ((zone->notifykeynames != NULL) && |
| 11679 | (zone->notifykeynames[i] != NULL)) { |
| 11680 | dns_view_t *view = dns_zone_getview(zone); |
| 11681 | dns_name_t *keyname = zone->notifykeynames[i]; |
| 11682 | (void)dns_view_gettsig(view, keyname, &key); |
| 11683 | } |
| 11684 | |
| 11685 | dst = zone->notify[i]; |
| 11686 | if (notify_isqueued(zone, flags, NULL, &dst, key)) { |
| 11687 | if (key != NULL) |
| 11688 | dns_tsigkey_detach(&key); |
| 11689 | continue; |
| 11690 | } |
| 11691 | |
| 11692 | result = notify_create(zone->mctx, flags, ¬ify); |
| 11693 | if (result != ISC_R_SUCCESS) { |
| 11694 | if (key != NULL) |
| 11695 | dns_tsigkey_detach(&key); |
| 11696 | continue; |
| 11697 | } |
| 11698 | |
| 11699 | zone_iattach(zone, ¬ify->zone); |
| 11700 | notify->dst = dst; |
| 11701 | |
| 11702 | INSIST(notify->key == NULL); |
| 11703 | |
| 11704 | if (key != NULL) { |
| 11705 | notify->key = key; |
| 11706 | key = NULL; |
| 11707 | } |
| 11708 | |
| 11709 | ISC_LIST_APPEND(zone->notifies, notify, link); |
| 11710 | result = notify_send_queue(notify, startup); |
| 11711 | if (result != ISC_R_SUCCESS) |
| 11712 | notify_destroy(notify, true); |
| 11713 | if (!loggednotify) { |
| 11714 | notify_log(zone, ISC_LOG_INFO, |
| 11715 | "sending notifies (serial %u)" , |
| 11716 | serial); |
| 11717 | loggednotify = true; |
| 11718 | } |
| 11719 | } |
| 11720 | UNLOCK_ZONE(zone); |
| 11721 | |
| 11722 | if (notifytype == dns_notifytype_explicit) |
| 11723 | goto cleanup3; |
| 11724 | |
| 11725 | /* |
| 11726 | * Process NS RRset to generate notifies. |
| 11727 | */ |
| 11728 | |
| 11729 | dns_rdataset_init(&nsrdset); |
| 11730 | result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_ns, |
| 11731 | dns_rdatatype_none, 0, &nsrdset, NULL); |
| 11732 | if (result != ISC_R_SUCCESS) |
| 11733 | goto cleanup3; |
| 11734 | |
| 11735 | result = dns_rdataset_first(&nsrdset); |
| 11736 | while (result == ISC_R_SUCCESS) { |
| 11737 | dns_notify_t *notify = NULL; |
| 11738 | |
| 11739 | dns_rdataset_current(&nsrdset, &rdata); |
| 11740 | result = dns_rdata_tostruct(&rdata, &ns, NULL); |
| 11741 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 11742 | dns_rdata_reset(&rdata); |
| 11743 | /* |
| 11744 | * Don't notify the master server unless explicitly |
| 11745 | * configured to do so. |
| 11746 | */ |
| 11747 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOTIFYTOSOA) && |
| 11748 | dns_name_compare(&master, &ns.name) == 0) { |
| 11749 | result = dns_rdataset_next(&nsrdset); |
| 11750 | continue; |
| 11751 | } |
| 11752 | |
| 11753 | if (!loggednotify) { |
| 11754 | notify_log(zone, ISC_LOG_INFO, |
| 11755 | "sending notifies (serial %u)" , |
| 11756 | serial); |
| 11757 | loggednotify = true; |
| 11758 | } |
| 11759 | |
| 11760 | LOCK_ZONE(zone); |
| 11761 | isqueued = notify_isqueued(zone, flags, &ns.name, NULL, NULL); |
| 11762 | UNLOCK_ZONE(zone); |
| 11763 | if (isqueued) { |
| 11764 | result = dns_rdataset_next(&nsrdset); |
| 11765 | continue; |
| 11766 | } |
| 11767 | result = notify_create(zone->mctx, flags, ¬ify); |
| 11768 | if (result != ISC_R_SUCCESS) |
| 11769 | continue; |
| 11770 | dns_zone_iattach(zone, ¬ify->zone); |
| 11771 | result = dns_name_dup(&ns.name, zone->mctx, ¬ify->ns); |
| 11772 | if (result != ISC_R_SUCCESS) { |
| 11773 | LOCK_ZONE(zone); |
| 11774 | notify_destroy(notify, true); |
| 11775 | UNLOCK_ZONE(zone); |
| 11776 | continue; |
| 11777 | } |
| 11778 | LOCK_ZONE(zone); |
| 11779 | ISC_LIST_APPEND(zone->notifies, notify, link); |
| 11780 | UNLOCK_ZONE(zone); |
| 11781 | notify_find_address(notify); |
| 11782 | result = dns_rdataset_next(&nsrdset); |
| 11783 | } |
| 11784 | dns_rdataset_disassociate(&nsrdset); |
| 11785 | |
| 11786 | cleanup3: |
| 11787 | if (dns_name_dynamic(&master)) |
| 11788 | dns_name_free(&master, zone->mctx); |
| 11789 | cleanup2: |
| 11790 | dns_db_detachnode(zonedb, &node); |
| 11791 | cleanup1: |
| 11792 | dns_db_closeversion(zonedb, &version, false); |
| 11793 | dns_db_detach(&zonedb); |
| 11794 | } |
| 11795 | |
| 11796 | /*** |
| 11797 | *** Private |
| 11798 | ***/ |
| 11799 | |
| 11800 | static inline isc_result_t |
| 11801 | save_nsrrset(dns_message_t *message, dns_name_t *name, |
| 11802 | dns_db_t *db, dns_dbversion_t *version) |
| 11803 | { |
| 11804 | dns_rdataset_t *nsrdataset = NULL; |
| 11805 | dns_rdataset_t *rdataset = NULL; |
| 11806 | dns_dbnode_t *node = NULL; |
| 11807 | dns_rdata_ns_t ns; |
| 11808 | isc_result_t result; |
| 11809 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 11810 | |
| 11811 | /* |
| 11812 | * Extract NS RRset from message. |
| 11813 | */ |
| 11814 | result = dns_message_findname(message, DNS_SECTION_ANSWER, name, |
| 11815 | dns_rdatatype_ns, dns_rdatatype_none, |
| 11816 | NULL, &nsrdataset); |
| 11817 | if (result != ISC_R_SUCCESS) |
| 11818 | goto fail; |
| 11819 | |
| 11820 | /* |
| 11821 | * Add NS rdataset. |
| 11822 | */ |
| 11823 | result = dns_db_findnode(db, name, true, &node); |
| 11824 | if (result != ISC_R_SUCCESS) |
| 11825 | goto fail; |
| 11826 | result = dns_db_addrdataset(db, node, version, 0, |
| 11827 | nsrdataset, 0, NULL); |
| 11828 | dns_db_detachnode(db, &node); |
| 11829 | if (result != ISC_R_SUCCESS) |
| 11830 | goto fail; |
| 11831 | /* |
| 11832 | * Add glue rdatasets. |
| 11833 | */ |
| 11834 | for (result = dns_rdataset_first(nsrdataset); |
| 11835 | result == ISC_R_SUCCESS; |
| 11836 | result = dns_rdataset_next(nsrdataset)) { |
| 11837 | dns_rdataset_current(nsrdataset, &rdata); |
| 11838 | result = dns_rdata_tostruct(&rdata, &ns, NULL); |
| 11839 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 11840 | dns_rdata_reset(&rdata); |
| 11841 | if (!dns_name_issubdomain(&ns.name, name)) |
| 11842 | continue; |
| 11843 | rdataset = NULL; |
| 11844 | result = dns_message_findname(message, DNS_SECTION_ADDITIONAL, |
| 11845 | &ns.name, dns_rdatatype_aaaa, |
| 11846 | dns_rdatatype_none, NULL, |
| 11847 | &rdataset); |
| 11848 | if (result == ISC_R_SUCCESS) { |
| 11849 | result = dns_db_findnode(db, &ns.name, |
| 11850 | true, &node); |
| 11851 | if (result != ISC_R_SUCCESS) |
| 11852 | goto fail; |
| 11853 | result = dns_db_addrdataset(db, node, version, 0, |
| 11854 | rdataset, 0, NULL); |
| 11855 | dns_db_detachnode(db, &node); |
| 11856 | if (result != ISC_R_SUCCESS) |
| 11857 | goto fail; |
| 11858 | } |
| 11859 | rdataset = NULL; |
| 11860 | result = dns_message_findname(message, DNS_SECTION_ADDITIONAL, |
| 11861 | &ns.name, dns_rdatatype_a, |
| 11862 | dns_rdatatype_none, NULL, |
| 11863 | &rdataset); |
| 11864 | if (result == ISC_R_SUCCESS) { |
| 11865 | result = dns_db_findnode(db, &ns.name, |
| 11866 | true, &node); |
| 11867 | if (result != ISC_R_SUCCESS) |
| 11868 | goto fail; |
| 11869 | result = dns_db_addrdataset(db, node, version, 0, |
| 11870 | rdataset, 0, NULL); |
| 11871 | dns_db_detachnode(db, &node); |
| 11872 | if (result != ISC_R_SUCCESS) |
| 11873 | goto fail; |
| 11874 | } |
| 11875 | } |
| 11876 | if (result != ISC_R_NOMORE) |
| 11877 | goto fail; |
| 11878 | |
| 11879 | return (ISC_R_SUCCESS); |
| 11880 | |
| 11881 | fail: |
| 11882 | return (result); |
| 11883 | } |
| 11884 | |
| 11885 | static void |
| 11886 | stub_callback(isc_task_t *task, isc_event_t *event) { |
| 11887 | const char me[] = "stub_callback" ; |
| 11888 | dns_requestevent_t *revent = (dns_requestevent_t *)event; |
| 11889 | dns_stub_t *stub = NULL; |
| 11890 | dns_message_t *msg = NULL; |
| 11891 | dns_zone_t *zone = NULL; |
| 11892 | char master[ISC_SOCKADDR_FORMATSIZE]; |
| 11893 | char source[ISC_SOCKADDR_FORMATSIZE]; |
| 11894 | uint32_t nscnt, cnamecnt, refresh, retry, expire; |
| 11895 | isc_result_t result; |
| 11896 | isc_time_t now; |
| 11897 | bool exiting = false; |
| 11898 | isc_interval_t i; |
| 11899 | unsigned int j, soacount; |
| 11900 | |
| 11901 | stub = revent->ev_arg; |
| 11902 | INSIST(DNS_STUB_VALID(stub)); |
| 11903 | |
| 11904 | UNUSED(task); |
| 11905 | |
| 11906 | zone = stub->zone; |
| 11907 | |
| 11908 | ENTER; |
| 11909 | |
| 11910 | TIME_NOW(&now); |
| 11911 | |
| 11912 | LOCK_ZONE(zone); |
| 11913 | |
| 11914 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { |
| 11915 | zone_debuglog(zone, me, 1, "exiting" ); |
| 11916 | exiting = true; |
| 11917 | goto next_master; |
| 11918 | } |
| 11919 | |
| 11920 | isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); |
| 11921 | isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); |
| 11922 | |
| 11923 | if (revent->result != ISC_R_SUCCESS) { |
| 11924 | if (revent->result == ISC_R_TIMEDOUT && |
| 11925 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { |
| 11926 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 11927 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 11928 | "refreshing stub: timeout retrying " |
| 11929 | " without EDNS master %s (source %s)" , |
| 11930 | master, source); |
| 11931 | goto same_master; |
| 11932 | } |
| 11933 | dns_zonemgr_unreachableadd(zone->zmgr, &zone->masteraddr, |
| 11934 | &zone->sourceaddr, &now); |
| 11935 | dns_zone_log(zone, ISC_LOG_INFO, |
| 11936 | "could not refresh stub from master %s" |
| 11937 | " (source %s): %s" , master, source, |
| 11938 | dns_result_totext(revent->result)); |
| 11939 | goto next_master; |
| 11940 | } |
| 11941 | |
| 11942 | result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); |
| 11943 | if (result != ISC_R_SUCCESS) |
| 11944 | goto next_master; |
| 11945 | |
| 11946 | result = dns_request_getresponse(revent->request, msg, 0); |
| 11947 | if (result != ISC_R_SUCCESS) |
| 11948 | goto next_master; |
| 11949 | |
| 11950 | /* |
| 11951 | * Unexpected rcode. |
| 11952 | */ |
| 11953 | if (msg->rcode != dns_rcode_noerror) { |
| 11954 | char rcode[128]; |
| 11955 | isc_buffer_t rb; |
| 11956 | |
| 11957 | isc_buffer_init(&rb, rcode, sizeof(rcode)); |
| 11958 | (void)dns_rcode_totext(msg->rcode, &rb); |
| 11959 | |
| 11960 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) && |
| 11961 | (msg->rcode == dns_rcode_servfail || |
| 11962 | msg->rcode == dns_rcode_notimp || |
| 11963 | msg->rcode == dns_rcode_formerr)) { |
| 11964 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 11965 | "refreshing stub: rcode (%.*s) retrying " |
| 11966 | "without EDNS master %s (source %s)" , |
| 11967 | (int)rb.used, rcode, master, source); |
| 11968 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 11969 | goto same_master; |
| 11970 | } |
| 11971 | |
| 11972 | dns_zone_log(zone, ISC_LOG_INFO, |
| 11973 | "refreshing stub: " |
| 11974 | "unexpected rcode (%.*s) from %s (source %s)" , |
| 11975 | (int)rb.used, rcode, master, source); |
| 11976 | goto next_master; |
| 11977 | } |
| 11978 | |
| 11979 | /* |
| 11980 | * We need complete messages. |
| 11981 | */ |
| 11982 | if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { |
| 11983 | if (dns_request_usedtcp(revent->request)) { |
| 11984 | dns_zone_log(zone, ISC_LOG_INFO, |
| 11985 | "refreshing stub: truncated TCP " |
| 11986 | "response from master %s (source %s)" , |
| 11987 | master, source); |
| 11988 | goto next_master; |
| 11989 | } |
| 11990 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC); |
| 11991 | goto same_master; |
| 11992 | } |
| 11993 | |
| 11994 | /* |
| 11995 | * If non-auth log and next master. |
| 11996 | */ |
| 11997 | if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) { |
| 11998 | dns_zone_log(zone, ISC_LOG_INFO, "refreshing stub: " |
| 11999 | "non-authoritative answer from " |
| 12000 | "master %s (source %s)" , master, source); |
| 12001 | goto next_master; |
| 12002 | } |
| 12003 | |
| 12004 | /* |
| 12005 | * Sanity checks. |
| 12006 | */ |
| 12007 | cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname); |
| 12008 | nscnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_ns); |
| 12009 | |
| 12010 | if (cnamecnt != 0) { |
| 12011 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12012 | "refreshing stub: unexpected CNAME response " |
| 12013 | "from master %s (source %s)" , master, source); |
| 12014 | goto next_master; |
| 12015 | } |
| 12016 | |
| 12017 | if (nscnt == 0) { |
| 12018 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12019 | "refreshing stub: no NS records in response " |
| 12020 | "from master %s (source %s)" , master, source); |
| 12021 | goto next_master; |
| 12022 | } |
| 12023 | |
| 12024 | /* |
| 12025 | * Save answer. |
| 12026 | */ |
| 12027 | result = save_nsrrset(msg, &zone->origin, stub->db, stub->version); |
| 12028 | if (result != ISC_R_SUCCESS) { |
| 12029 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12030 | "refreshing stub: unable to save NS records " |
| 12031 | "from master %s (source %s)" , master, source); |
| 12032 | goto next_master; |
| 12033 | } |
| 12034 | |
| 12035 | /* |
| 12036 | * Tidy up. |
| 12037 | */ |
| 12038 | dns_db_closeversion(stub->db, &stub->version, true); |
| 12039 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); |
| 12040 | if (zone->db == NULL) |
| 12041 | zone_attachdb(zone, stub->db); |
| 12042 | result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL, |
| 12043 | &refresh, &retry, &expire, NULL, NULL); |
| 12044 | if (result == ISC_R_SUCCESS && soacount > 0U) { |
| 12045 | zone->refresh = RANGE(refresh, zone->minrefresh, |
| 12046 | zone->maxrefresh); |
| 12047 | zone->retry = RANGE(retry, zone->minretry, zone->maxretry); |
| 12048 | zone->expire = RANGE(expire, zone->refresh + zone->retry, |
| 12049 | DNS_MAX_EXPIRE); |
| 12050 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); |
| 12051 | } |
| 12052 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
| 12053 | dns_db_detach(&stub->db); |
| 12054 | |
| 12055 | dns_message_destroy(&msg); |
| 12056 | isc_event_free(&event); |
| 12057 | dns_request_destroy(&zone->request); |
| 12058 | |
| 12059 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 12060 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); |
| 12061 | DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); |
| 12062 | isc_interval_set(&i, zone->expire, 0); |
| 12063 | DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); |
| 12064 | |
| 12065 | if (zone->masterfile != NULL) |
| 12066 | zone_needdump(zone, 0); |
| 12067 | |
| 12068 | zone_settimer(zone, &now); |
| 12069 | goto free_stub; |
| 12070 | |
| 12071 | next_master: |
| 12072 | if (stub->version != NULL) |
| 12073 | dns_db_closeversion(stub->db, &stub->version, false); |
| 12074 | if (stub->db != NULL) |
| 12075 | dns_db_detach(&stub->db); |
| 12076 | if (msg != NULL) |
| 12077 | dns_message_destroy(&msg); |
| 12078 | isc_event_free(&event); |
| 12079 | dns_request_destroy(&zone->request); |
| 12080 | /* |
| 12081 | * Skip to next failed / untried master. |
| 12082 | */ |
| 12083 | do { |
| 12084 | zone->curmaster++; |
| 12085 | } while (zone->curmaster < zone->masterscnt && |
| 12086 | zone->mastersok[zone->curmaster]); |
| 12087 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 12088 | if (exiting || zone->curmaster >= zone->masterscnt) { |
| 12089 | bool done = true; |
| 12090 | if (!exiting && |
| 12091 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && |
| 12092 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { |
| 12093 | /* |
| 12094 | * Did we get a good answer from all the masters? |
| 12095 | */ |
| 12096 | for (j = 0; j < zone->masterscnt; j++) |
| 12097 | if (zone->mastersok[j] == false) { |
| 12098 | done = false; |
| 12099 | break; |
| 12100 | } |
| 12101 | } else |
| 12102 | done = true; |
| 12103 | if (!done) { |
| 12104 | zone->curmaster = 0; |
| 12105 | /* |
| 12106 | * Find the next failed master. |
| 12107 | */ |
| 12108 | while (zone->curmaster < zone->masterscnt && |
| 12109 | zone->mastersok[zone->curmaster]) |
| 12110 | zone->curmaster++; |
| 12111 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); |
| 12112 | } else { |
| 12113 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 12114 | |
| 12115 | zone_settimer(zone, &now); |
| 12116 | goto free_stub; |
| 12117 | } |
| 12118 | } |
| 12119 | queue_soa_query(zone); |
| 12120 | goto free_stub; |
| 12121 | |
| 12122 | same_master: |
| 12123 | if (msg != NULL) |
| 12124 | dns_message_destroy(&msg); |
| 12125 | isc_event_free(&event); |
| 12126 | dns_request_destroy(&zone->request); |
| 12127 | ns_query(zone, NULL, stub); |
| 12128 | UNLOCK_ZONE(zone); |
| 12129 | goto done; |
| 12130 | |
| 12131 | free_stub: |
| 12132 | UNLOCK_ZONE(zone); |
| 12133 | stub->magic = 0; |
| 12134 | dns_zone_idetach(&stub->zone); |
| 12135 | INSIST(stub->db == NULL); |
| 12136 | INSIST(stub->version == NULL); |
| 12137 | isc_mem_put(stub->mctx, stub, sizeof(*stub)); |
| 12138 | |
| 12139 | done: |
| 12140 | INSIST(event == NULL); |
| 12141 | return; |
| 12142 | } |
| 12143 | |
| 12144 | /* |
| 12145 | * Get the EDNS EXPIRE option from the response and if it exists trim |
| 12146 | * expire to be not more than it. |
| 12147 | */ |
| 12148 | static void |
| 12149 | get_edns_expire(dns_zone_t * zone, dns_message_t *message, |
| 12150 | uint32_t *expirep) |
| 12151 | { |
| 12152 | isc_result_t result; |
| 12153 | uint32_t expire; |
| 12154 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 12155 | isc_buffer_t optbuf; |
| 12156 | uint16_t optcode; |
| 12157 | uint16_t optlen; |
| 12158 | |
| 12159 | REQUIRE(expirep != NULL); |
| 12160 | REQUIRE(message != NULL); |
| 12161 | |
| 12162 | if (message->opt == NULL) |
| 12163 | return; |
| 12164 | |
| 12165 | result = dns_rdataset_first(message->opt); |
| 12166 | if (result == ISC_R_SUCCESS) { |
| 12167 | dns_rdataset_current(message->opt, &rdata); |
| 12168 | isc_buffer_init(&optbuf, rdata.data, rdata.length); |
| 12169 | isc_buffer_add(&optbuf, rdata.length); |
| 12170 | while (isc_buffer_remaininglength(&optbuf) >= 4) { |
| 12171 | optcode = isc_buffer_getuint16(&optbuf); |
| 12172 | optlen = isc_buffer_getuint16(&optbuf); |
| 12173 | /* |
| 12174 | * A EDNS EXPIRE response has a length of 4. |
| 12175 | */ |
| 12176 | if (optcode != DNS_OPT_EXPIRE || optlen != 4) { |
| 12177 | isc_buffer_forward(&optbuf, optlen); |
| 12178 | continue; |
| 12179 | } |
| 12180 | expire = isc_buffer_getuint32(&optbuf); |
| 12181 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 12182 | "got EDNS EXPIRE of %u" , expire); |
| 12183 | /* |
| 12184 | * Trim *expirep? |
| 12185 | */ |
| 12186 | if (expire < *expirep) |
| 12187 | *expirep = expire; |
| 12188 | break; |
| 12189 | } |
| 12190 | } |
| 12191 | } |
| 12192 | |
| 12193 | /* |
| 12194 | * Set the file modification time zone->expire seconds before expiretime. |
| 12195 | */ |
| 12196 | static void |
| 12197 | setmodtime(dns_zone_t *zone, isc_time_t *expiretime) { |
| 12198 | isc_result_t result; |
| 12199 | isc_time_t when; |
| 12200 | isc_interval_t i; |
| 12201 | |
| 12202 | isc_interval_set(&i, zone->expire, 0); |
| 12203 | result = isc_time_subtract(expiretime, &i, &when); |
| 12204 | if (result != ISC_R_SUCCESS) |
| 12205 | return; |
| 12206 | |
| 12207 | result = ISC_R_FAILURE; |
| 12208 | if (zone->journal != NULL) |
| 12209 | result = isc_file_settime(zone->journal, &when); |
| 12210 | if (result == ISC_R_SUCCESS && |
| 12211 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && |
| 12212 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP)) |
| 12213 | result = isc_file_settime(zone->masterfile, &when); |
| 12214 | else if (result != ISC_R_SUCCESS) |
| 12215 | result = isc_file_settime(zone->masterfile, &when); |
| 12216 | |
| 12217 | /* |
| 12218 | * Someone removed the file from underneath us! |
| 12219 | */ |
| 12220 | if (result == ISC_R_FILENOTFOUND) { |
| 12221 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 12222 | } else if (result != ISC_R_SUCCESS) |
| 12223 | dns_zone_log(zone, ISC_LOG_ERROR, "refresh: could not set " |
| 12224 | "file modification time of '%s': %s" , |
| 12225 | zone->masterfile, dns_result_totext(result)); |
| 12226 | } |
| 12227 | |
| 12228 | /* |
| 12229 | * An SOA query has finished (successfully or not). |
| 12230 | */ |
| 12231 | static void |
| 12232 | refresh_callback(isc_task_t *task, isc_event_t *event) { |
| 12233 | const char me[] = "refresh_callback" ; |
| 12234 | dns_requestevent_t *revent = (dns_requestevent_t *)event; |
| 12235 | dns_zone_t *zone; |
| 12236 | dns_message_t *msg = NULL; |
| 12237 | uint32_t soacnt, cnamecnt, soacount, nscount; |
| 12238 | isc_time_t now; |
| 12239 | char master[ISC_SOCKADDR_FORMATSIZE]; |
| 12240 | char source[ISC_SOCKADDR_FORMATSIZE]; |
| 12241 | dns_rdataset_t *rdataset = NULL; |
| 12242 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 12243 | dns_rdata_soa_t soa; |
| 12244 | isc_result_t result; |
| 12245 | uint32_t serial, oldserial = 0; |
| 12246 | unsigned int j; |
| 12247 | bool do_queue_xfrin = false; |
| 12248 | |
| 12249 | zone = revent->ev_arg; |
| 12250 | INSIST(DNS_ZONE_VALID(zone)); |
| 12251 | |
| 12252 | UNUSED(task); |
| 12253 | |
| 12254 | ENTER; |
| 12255 | |
| 12256 | TIME_NOW(&now); |
| 12257 | |
| 12258 | LOCK_ZONE(zone); |
| 12259 | |
| 12260 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { |
| 12261 | isc_event_free(&event); |
| 12262 | dns_request_destroy(&zone->request); |
| 12263 | goto detach; |
| 12264 | } |
| 12265 | |
| 12266 | /* |
| 12267 | * if timeout log and next master; |
| 12268 | */ |
| 12269 | |
| 12270 | isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); |
| 12271 | isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); |
| 12272 | |
| 12273 | if (revent->result != ISC_R_SUCCESS) { |
| 12274 | if (revent->result == ISC_R_TIMEDOUT && |
| 12275 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { |
| 12276 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 12277 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 12278 | "refresh: timeout retrying without EDNS " |
| 12279 | "master %s (source %s)" , master, source); |
| 12280 | goto same_master; |
| 12281 | } |
| 12282 | if (revent->result == ISC_R_TIMEDOUT && |
| 12283 | !dns_request_usedtcp(revent->request)) { |
| 12284 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12285 | "refresh: retry limit for " |
| 12286 | "master %s exceeded (source %s)" , |
| 12287 | master, source); |
| 12288 | /* Try with slave with TCP. */ |
| 12289 | if ((zone->type == dns_zone_slave || |
| 12290 | zone->type == dns_zone_mirror || |
| 12291 | zone->type == dns_zone_redirect) && |
| 12292 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH)) |
| 12293 | { |
| 12294 | if (!dns_zonemgr_unreachable(zone->zmgr, |
| 12295 | &zone->masteraddr, |
| 12296 | &zone->sourceaddr, |
| 12297 | &now)) |
| 12298 | { |
| 12299 | DNS_ZONE_SETFLAG(zone, |
| 12300 | DNS_ZONEFLG_SOABEFOREAXFR); |
| 12301 | goto tcp_transfer; |
| 12302 | } |
| 12303 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 12304 | "refresh: skipped tcp fallback " |
| 12305 | "as master %s (source %s) is " |
| 12306 | "unreachable (cached)" , |
| 12307 | master, source); |
| 12308 | } |
| 12309 | } else |
| 12310 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12311 | "refresh: failure trying master " |
| 12312 | "%s (source %s): %s" , master, source, |
| 12313 | dns_result_totext(revent->result)); |
| 12314 | goto next_master; |
| 12315 | } |
| 12316 | |
| 12317 | result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); |
| 12318 | if (result != ISC_R_SUCCESS) |
| 12319 | goto next_master; |
| 12320 | result = dns_request_getresponse(revent->request, msg, 0); |
| 12321 | if (result != ISC_R_SUCCESS) { |
| 12322 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12323 | "refresh: failure trying master " |
| 12324 | "%s (source %s): %s" , master, source, |
| 12325 | dns_result_totext(result)); |
| 12326 | goto next_master; |
| 12327 | } |
| 12328 | |
| 12329 | /* |
| 12330 | * Unexpected rcode. |
| 12331 | */ |
| 12332 | if (msg->rcode != dns_rcode_noerror) { |
| 12333 | char rcode[128]; |
| 12334 | isc_buffer_t rb; |
| 12335 | |
| 12336 | isc_buffer_init(&rb, rcode, sizeof(rcode)); |
| 12337 | (void)dns_rcode_totext(msg->rcode, &rb); |
| 12338 | |
| 12339 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) && |
| 12340 | (msg->rcode == dns_rcode_servfail || |
| 12341 | msg->rcode == dns_rcode_notimp || |
| 12342 | msg->rcode == dns_rcode_formerr)) { |
| 12343 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 12344 | "refresh: rcode (%.*s) retrying without " |
| 12345 | "EDNS master %s (source %s)" , |
| 12346 | (int)rb.used, rcode, master, source); |
| 12347 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 12348 | goto same_master; |
| 12349 | } |
| 12350 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) && |
| 12351 | msg->rcode == dns_rcode_badvers) { |
| 12352 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 12353 | "refresh: rcode (%.*s) retrying without " |
| 12354 | "EDNS EXPIRE OPTION master %s (source %s)" , |
| 12355 | (int)rb.used, rcode, master, source); |
| 12356 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 12357 | goto same_master; |
| 12358 | } |
| 12359 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12360 | "refresh: unexpected rcode (%.*s) from " |
| 12361 | "master %s (source %s)" , (int)rb.used, rcode, |
| 12362 | master, source); |
| 12363 | /* |
| 12364 | * Perhaps AXFR/IXFR is allowed even if SOA queries aren't. |
| 12365 | */ |
| 12366 | if (msg->rcode == dns_rcode_refused && |
| 12367 | (zone->type == dns_zone_slave || |
| 12368 | zone->type == dns_zone_mirror || |
| 12369 | zone->type == dns_zone_redirect)) |
| 12370 | { |
| 12371 | goto tcp_transfer; |
| 12372 | } |
| 12373 | goto next_master; |
| 12374 | } |
| 12375 | |
| 12376 | /* |
| 12377 | * If truncated punt to zone transfer which will query again. |
| 12378 | */ |
| 12379 | if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { |
| 12380 | if (zone->type == dns_zone_slave || |
| 12381 | zone->type == dns_zone_mirror || |
| 12382 | zone->type == dns_zone_redirect) |
| 12383 | { |
| 12384 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12385 | "refresh: truncated UDP answer, " |
| 12386 | "initiating TCP zone xfer " |
| 12387 | "for master %s (source %s)" , |
| 12388 | master, source); |
| 12389 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); |
| 12390 | goto tcp_transfer; |
| 12391 | } else { |
| 12392 | INSIST(zone->type == dns_zone_stub); |
| 12393 | if (dns_request_usedtcp(revent->request)) { |
| 12394 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12395 | "refresh: truncated TCP response " |
| 12396 | "from master %s (source %s)" , |
| 12397 | master, source); |
| 12398 | goto next_master; |
| 12399 | } |
| 12400 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC); |
| 12401 | goto same_master; |
| 12402 | } |
| 12403 | } |
| 12404 | |
| 12405 | /* |
| 12406 | * if non-auth log and next master; |
| 12407 | */ |
| 12408 | if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) { |
| 12409 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12410 | "refresh: non-authoritative answer from " |
| 12411 | "master %s (source %s)" , master, source); |
| 12412 | goto next_master; |
| 12413 | } |
| 12414 | |
| 12415 | cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname); |
| 12416 | soacnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_soa); |
| 12417 | nscount = message_count(msg, DNS_SECTION_AUTHORITY, dns_rdatatype_ns); |
| 12418 | soacount = message_count(msg, DNS_SECTION_AUTHORITY, |
| 12419 | dns_rdatatype_soa); |
| 12420 | |
| 12421 | /* |
| 12422 | * There should not be a CNAME record at top of zone. |
| 12423 | */ |
| 12424 | if (cnamecnt != 0) { |
| 12425 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12426 | "refresh: CNAME at top of zone " |
| 12427 | "in master %s (source %s)" , master, source); |
| 12428 | goto next_master; |
| 12429 | } |
| 12430 | |
| 12431 | /* |
| 12432 | * if referral log and next master; |
| 12433 | */ |
| 12434 | if (soacnt == 0 && soacount == 0 && nscount != 0) { |
| 12435 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12436 | "refresh: referral response " |
| 12437 | "from master %s (source %s)" , master, source); |
| 12438 | goto next_master; |
| 12439 | } |
| 12440 | |
| 12441 | /* |
| 12442 | * if nodata log and next master; |
| 12443 | */ |
| 12444 | if (soacnt == 0 && (nscount == 0 || soacount != 0)) { |
| 12445 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12446 | "refresh: NODATA response " |
| 12447 | "from master %s (source %s)" , master, source); |
| 12448 | goto next_master; |
| 12449 | } |
| 12450 | |
| 12451 | /* |
| 12452 | * Only one soa at top of zone. |
| 12453 | */ |
| 12454 | if (soacnt != 1) { |
| 12455 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12456 | "refresh: answer SOA count (%d) != 1 " |
| 12457 | "from master %s (source %s)" , |
| 12458 | soacnt, master, source); |
| 12459 | goto next_master; |
| 12460 | } |
| 12461 | |
| 12462 | /* |
| 12463 | * Extract serial |
| 12464 | */ |
| 12465 | rdataset = NULL; |
| 12466 | result = dns_message_findname(msg, DNS_SECTION_ANSWER, &zone->origin, |
| 12467 | dns_rdatatype_soa, dns_rdatatype_none, |
| 12468 | NULL, &rdataset); |
| 12469 | if (result != ISC_R_SUCCESS) { |
| 12470 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12471 | "refresh: unable to get SOA record " |
| 12472 | "from master %s (source %s)" , master, source); |
| 12473 | goto next_master; |
| 12474 | } |
| 12475 | |
| 12476 | result = dns_rdataset_first(rdataset); |
| 12477 | if (result != ISC_R_SUCCESS) { |
| 12478 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12479 | "refresh: dns_rdataset_first() failed" ); |
| 12480 | goto next_master; |
| 12481 | } |
| 12482 | |
| 12483 | dns_rdataset_current(rdataset, &rdata); |
| 12484 | result = dns_rdata_tostruct(&rdata, &soa, NULL); |
| 12485 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 12486 | |
| 12487 | serial = soa.serial; |
| 12488 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { |
| 12489 | unsigned int dbsoacount; |
| 12490 | result = zone_get_from_db(zone, zone->db, NULL, &dbsoacount, |
| 12491 | &oldserial, NULL, NULL, NULL, NULL, |
| 12492 | NULL); |
| 12493 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 12494 | RUNTIME_CHECK(dbsoacount > 0U); |
| 12495 | zone_debuglog(zone, me, 1, "serial: new %u, old %u" , |
| 12496 | serial, oldserial); |
| 12497 | } else |
| 12498 | zone_debuglog(zone, me, 1, "serial: new %u, old not loaded" , |
| 12499 | serial); |
| 12500 | |
| 12501 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) || |
| 12502 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) || |
| 12503 | isc_serial_gt(serial, oldserial)) { |
| 12504 | if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, |
| 12505 | &zone->sourceaddr, &now)) |
| 12506 | { |
| 12507 | dns_zone_log(zone, ISC_LOG_INFO, |
| 12508 | "refresh: skipping %s as master %s " |
| 12509 | "(source %s) is unreachable (cached)" , |
| 12510 | (zone->type == dns_zone_slave || |
| 12511 | zone->type == dns_zone_mirror || |
| 12512 | zone->type == dns_zone_redirect) ? |
| 12513 | "zone transfer" : "NS query" , |
| 12514 | master, source); |
| 12515 | goto next_master; |
| 12516 | } |
| 12517 | tcp_transfer: |
| 12518 | isc_event_free(&event); |
| 12519 | dns_request_destroy(&zone->request); |
| 12520 | if (zone->type == dns_zone_slave || |
| 12521 | zone->type == dns_zone_mirror || |
| 12522 | zone->type == dns_zone_redirect) |
| 12523 | { |
| 12524 | do_queue_xfrin = true; |
| 12525 | } else { |
| 12526 | INSIST(zone->type == dns_zone_stub); |
| 12527 | ns_query(zone, rdataset, NULL); |
| 12528 | } |
| 12529 | if (msg != NULL) |
| 12530 | dns_message_destroy(&msg); |
| 12531 | } else if (isc_serial_eq(soa.serial, oldserial)) { |
| 12532 | isc_time_t expiretime; |
| 12533 | uint32_t expire; |
| 12534 | |
| 12535 | /* |
| 12536 | * Compute the new expire time based on this response. |
| 12537 | */ |
| 12538 | expire = zone->expire; |
| 12539 | get_edns_expire(zone, msg, &expire); |
| 12540 | DNS_ZONE_TIME_ADD(&now, expire, &expiretime); |
| 12541 | |
| 12542 | /* |
| 12543 | * Has the expire time improved? |
| 12544 | */ |
| 12545 | if (isc_time_compare(&expiretime, &zone->expiretime) > 0) { |
| 12546 | zone->expiretime = expiretime; |
| 12547 | if (zone->masterfile != NULL) |
| 12548 | setmodtime(zone, &expiretime); |
| 12549 | } |
| 12550 | |
| 12551 | DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); |
| 12552 | zone->mastersok[zone->curmaster] = true; |
| 12553 | goto next_master; |
| 12554 | } else { |
| 12555 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MULTIMASTER)) |
| 12556 | dns_zone_log(zone, ISC_LOG_INFO, "serial number (%u) " |
| 12557 | "received from master %s < ours (%u)" , |
| 12558 | soa.serial, master, oldserial); |
| 12559 | else |
| 12560 | zone_debuglog(zone, me, 1, "ahead" ); |
| 12561 | zone->mastersok[zone->curmaster] = true; |
| 12562 | goto next_master; |
| 12563 | } |
| 12564 | if (msg != NULL) |
| 12565 | dns_message_destroy(&msg); |
| 12566 | goto detach; |
| 12567 | |
| 12568 | next_master: |
| 12569 | if (msg != NULL) |
| 12570 | dns_message_destroy(&msg); |
| 12571 | isc_event_free(&event); |
| 12572 | dns_request_destroy(&zone->request); |
| 12573 | /* |
| 12574 | * Skip to next failed / untried master. |
| 12575 | */ |
| 12576 | do { |
| 12577 | zone->curmaster++; |
| 12578 | } while (zone->curmaster < zone->masterscnt && |
| 12579 | zone->mastersok[zone->curmaster]); |
| 12580 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 12581 | if (zone->curmaster >= zone->masterscnt) { |
| 12582 | bool done = true; |
| 12583 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && |
| 12584 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { |
| 12585 | /* |
| 12586 | * Did we get a good answer from all the masters? |
| 12587 | */ |
| 12588 | for (j = 0; j < zone->masterscnt; j++) |
| 12589 | if (zone->mastersok[j] == false) { |
| 12590 | done = false; |
| 12591 | break; |
| 12592 | } |
| 12593 | } else |
| 12594 | done = true; |
| 12595 | if (!done) { |
| 12596 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); |
| 12597 | zone->curmaster = 0; |
| 12598 | /* |
| 12599 | * Find the next failed master. |
| 12600 | */ |
| 12601 | while (zone->curmaster < zone->masterscnt && |
| 12602 | zone->mastersok[zone->curmaster]) |
| 12603 | zone->curmaster++; |
| 12604 | goto requeue; |
| 12605 | } |
| 12606 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 12607 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) { |
| 12608 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); |
| 12609 | zone->refreshtime = now; |
| 12610 | } |
| 12611 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); |
| 12612 | zone_settimer(zone, &now); |
| 12613 | goto detach; |
| 12614 | } |
| 12615 | |
| 12616 | requeue: |
| 12617 | queue_soa_query(zone); |
| 12618 | goto detach; |
| 12619 | |
| 12620 | same_master: |
| 12621 | if (msg != NULL) |
| 12622 | dns_message_destroy(&msg); |
| 12623 | isc_event_free(&event); |
| 12624 | dns_request_destroy(&zone->request); |
| 12625 | queue_soa_query(zone); |
| 12626 | |
| 12627 | detach: |
| 12628 | UNLOCK_ZONE(zone); |
| 12629 | if (do_queue_xfrin) |
| 12630 | queue_xfrin(zone); |
| 12631 | dns_zone_idetach(&zone); |
| 12632 | return; |
| 12633 | } |
| 12634 | |
| 12635 | static void |
| 12636 | queue_soa_query(dns_zone_t *zone) { |
| 12637 | const char me[] = "queue_soa_query" ; |
| 12638 | isc_event_t *e; |
| 12639 | dns_zone_t *dummy = NULL; |
| 12640 | isc_result_t result; |
| 12641 | |
| 12642 | ENTER; |
| 12643 | /* |
| 12644 | * Locked by caller |
| 12645 | */ |
| 12646 | REQUIRE(LOCKED_ZONE(zone)); |
| 12647 | |
| 12648 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { |
| 12649 | cancel_refresh(zone); |
| 12650 | return; |
| 12651 | } |
| 12652 | |
| 12653 | e = isc_event_allocate(zone->mctx, NULL, DNS_EVENT_ZONE, |
| 12654 | soa_query, zone, sizeof(isc_event_t)); |
| 12655 | if (e == NULL) { |
| 12656 | cancel_refresh(zone); |
| 12657 | return; |
| 12658 | } |
| 12659 | |
| 12660 | /* |
| 12661 | * Attach so that we won't clean up |
| 12662 | * until the event is delivered. |
| 12663 | */ |
| 12664 | zone_iattach(zone, &dummy); |
| 12665 | |
| 12666 | e->ev_arg = zone; |
| 12667 | e->ev_sender = NULL; |
| 12668 | result = isc_ratelimiter_enqueue(zone->zmgr->refreshrl, zone->task, &e); |
| 12669 | if (result != ISC_R_SUCCESS) { |
| 12670 | zone_idetach(&dummy); |
| 12671 | isc_event_free(&e); |
| 12672 | cancel_refresh(zone); |
| 12673 | } |
| 12674 | } |
| 12675 | |
| 12676 | static inline isc_result_t |
| 12677 | create_query(dns_zone_t *zone, dns_rdatatype_t rdtype, |
| 12678 | dns_message_t **messagep) |
| 12679 | { |
| 12680 | dns_message_t *message = NULL; |
| 12681 | dns_name_t *qname = NULL; |
| 12682 | dns_rdataset_t *qrdataset = NULL; |
| 12683 | isc_result_t result; |
| 12684 | |
| 12685 | result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, |
| 12686 | &message); |
| 12687 | if (result != ISC_R_SUCCESS) |
| 12688 | goto cleanup; |
| 12689 | |
| 12690 | message->opcode = dns_opcode_query; |
| 12691 | message->rdclass = zone->rdclass; |
| 12692 | |
| 12693 | result = dns_message_gettempname(message, &qname); |
| 12694 | if (result != ISC_R_SUCCESS) |
| 12695 | goto cleanup; |
| 12696 | |
| 12697 | result = dns_message_gettemprdataset(message, &qrdataset); |
| 12698 | if (result != ISC_R_SUCCESS) |
| 12699 | goto cleanup; |
| 12700 | |
| 12701 | /* |
| 12702 | * Make question. |
| 12703 | */ |
| 12704 | dns_name_init(qname, NULL); |
| 12705 | dns_name_clone(&zone->origin, qname); |
| 12706 | dns_rdataset_makequestion(qrdataset, zone->rdclass, rdtype); |
| 12707 | ISC_LIST_APPEND(qname->list, qrdataset, link); |
| 12708 | dns_message_addname(message, qname, DNS_SECTION_QUESTION); |
| 12709 | |
| 12710 | *messagep = message; |
| 12711 | return (ISC_R_SUCCESS); |
| 12712 | |
| 12713 | cleanup: |
| 12714 | if (qname != NULL) |
| 12715 | dns_message_puttempname(message, &qname); |
| 12716 | if (qrdataset != NULL) |
| 12717 | dns_message_puttemprdataset(message, &qrdataset); |
| 12718 | if (message != NULL) |
| 12719 | dns_message_destroy(&message); |
| 12720 | return (result); |
| 12721 | } |
| 12722 | |
| 12723 | static isc_result_t |
| 12724 | add_opt(dns_message_t *message, uint16_t udpsize, bool reqnsid, |
| 12725 | bool reqexpire) |
| 12726 | { |
| 12727 | isc_result_t result; |
| 12728 | dns_rdataset_t *rdataset = NULL; |
| 12729 | dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; |
| 12730 | int count = 0; |
| 12731 | |
| 12732 | /* Set EDNS options if applicable */ |
| 12733 | if (reqnsid) { |
| 12734 | INSIST(count < DNS_EDNSOPTIONS); |
| 12735 | ednsopts[count].code = DNS_OPT_NSID; |
| 12736 | ednsopts[count].length = 0; |
| 12737 | ednsopts[count].value = NULL; |
| 12738 | count++; |
| 12739 | } |
| 12740 | if (reqexpire) { |
| 12741 | INSIST(count < DNS_EDNSOPTIONS); |
| 12742 | ednsopts[count].code = DNS_OPT_EXPIRE; |
| 12743 | ednsopts[count].length = 0; |
| 12744 | ednsopts[count].value = NULL; |
| 12745 | count++; |
| 12746 | } |
| 12747 | result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0, |
| 12748 | ednsopts, count); |
| 12749 | if (result != ISC_R_SUCCESS) |
| 12750 | return (result); |
| 12751 | |
| 12752 | return (dns_message_setopt(message, rdataset)); |
| 12753 | } |
| 12754 | |
| 12755 | static void |
| 12756 | soa_query(isc_task_t *task, isc_event_t *event) { |
| 12757 | const char me[] = "soa_query" ; |
| 12758 | isc_result_t result = ISC_R_FAILURE; |
| 12759 | dns_message_t *message = NULL; |
| 12760 | dns_zone_t *zone = event->ev_arg; |
| 12761 | dns_zone_t *dummy = NULL; |
| 12762 | isc_netaddr_t masterip; |
| 12763 | dns_tsigkey_t *key = NULL; |
| 12764 | uint32_t options; |
| 12765 | bool cancel = true; |
| 12766 | int timeout; |
| 12767 | bool have_xfrsource, have_xfrdscp, reqnsid, reqexpire; |
| 12768 | uint16_t udpsize = SEND_BUFFER_SIZE; |
| 12769 | isc_dscp_t dscp = -1; |
| 12770 | |
| 12771 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 12772 | |
| 12773 | UNUSED(task); |
| 12774 | |
| 12775 | ENTER; |
| 12776 | |
| 12777 | LOCK_ZONE(zone); |
| 12778 | if (((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) || |
| 12779 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || |
| 12780 | zone->view->requestmgr == NULL) { |
| 12781 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) |
| 12782 | cancel = false; |
| 12783 | goto cleanup; |
| 12784 | } |
| 12785 | |
| 12786 | again: |
| 12787 | result = create_query(zone, dns_rdatatype_soa, &message); |
| 12788 | if (result != ISC_R_SUCCESS) |
| 12789 | goto cleanup; |
| 12790 | |
| 12791 | INSIST(zone->masterscnt > 0); |
| 12792 | INSIST(zone->curmaster < zone->masterscnt); |
| 12793 | |
| 12794 | zone->masteraddr = zone->masters[zone->curmaster]; |
| 12795 | |
| 12796 | isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); |
| 12797 | /* |
| 12798 | * First, look for a tsig key in the master statement, then |
| 12799 | * try for a server key. |
| 12800 | */ |
| 12801 | if ((zone->masterkeynames != NULL) && |
| 12802 | (zone->masterkeynames[zone->curmaster] != NULL)) { |
| 12803 | dns_view_t *view = dns_zone_getview(zone); |
| 12804 | dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; |
| 12805 | result = dns_view_gettsig(view, keyname, &key); |
| 12806 | if (result != ISC_R_SUCCESS) { |
| 12807 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 12808 | dns_name_format(keyname, namebuf, sizeof(namebuf)); |
| 12809 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 12810 | "unable to find key: %s" , namebuf); |
| 12811 | goto skip_master; |
| 12812 | } |
| 12813 | } |
| 12814 | if (key == NULL) { |
| 12815 | result = dns_view_getpeertsig(zone->view, &masterip, &key); |
| 12816 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { |
| 12817 | char addrbuf[ISC_NETADDR_FORMATSIZE]; |
| 12818 | isc_netaddr_format(&masterip, addrbuf, sizeof(addrbuf)); |
| 12819 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 12820 | "unable to find TSIG key for %s" , addrbuf); |
| 12821 | goto skip_master; |
| 12822 | } |
| 12823 | } |
| 12824 | |
| 12825 | options = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEVC) ? |
| 12826 | DNS_REQUESTOPT_TCP : 0; |
| 12827 | have_xfrsource = have_xfrdscp = false; |
| 12828 | reqnsid = zone->view->requestnsid; |
| 12829 | reqexpire = zone->requestexpire; |
| 12830 | if (zone->view->peers != NULL) { |
| 12831 | dns_peer_t *peer = NULL; |
| 12832 | bool edns, usetcp; |
| 12833 | result = dns_peerlist_peerbyaddr(zone->view->peers, |
| 12834 | &masterip, &peer); |
| 12835 | if (result == ISC_R_SUCCESS) { |
| 12836 | result = dns_peer_getsupportedns(peer, &edns); |
| 12837 | if (result == ISC_R_SUCCESS && !edns) |
| 12838 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 12839 | result = dns_peer_gettransfersource(peer, |
| 12840 | &zone->sourceaddr); |
| 12841 | if (result == ISC_R_SUCCESS) |
| 12842 | have_xfrsource = true; |
| 12843 | (void)dns_peer_gettransferdscp(peer, &dscp); |
| 12844 | if (dscp != -1) |
| 12845 | have_xfrdscp = true; |
| 12846 | if (zone->view->resolver != NULL) |
| 12847 | udpsize = |
| 12848 | dns_resolver_getudpsize(zone->view->resolver); |
| 12849 | (void)dns_peer_getudpsize(peer, &udpsize); |
| 12850 | (void)dns_peer_getrequestnsid(peer, &reqnsid); |
| 12851 | (void)dns_peer_getrequestexpire(peer, &reqexpire); |
| 12852 | result = dns_peer_getforcetcp(peer, &usetcp); |
| 12853 | if (result == ISC_R_SUCCESS && usetcp) |
| 12854 | options |= DNS_REQUESTOPT_TCP; |
| 12855 | } |
| 12856 | } |
| 12857 | |
| 12858 | switch (isc_sockaddr_pf(&zone->masteraddr)) { |
| 12859 | case PF_INET: |
| 12860 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { |
| 12861 | if (isc_sockaddr_equal(&zone->altxfrsource4, |
| 12862 | &zone->xfrsource4)) |
| 12863 | goto skip_master; |
| 12864 | zone->sourceaddr = zone->altxfrsource4; |
| 12865 | if (!have_xfrdscp) |
| 12866 | dscp = zone->altxfrsource4dscp; |
| 12867 | } else if (!have_xfrsource) { |
| 12868 | zone->sourceaddr = zone->xfrsource4; |
| 12869 | if (!have_xfrdscp) |
| 12870 | dscp = zone->xfrsource4dscp; |
| 12871 | } |
| 12872 | break; |
| 12873 | case PF_INET6: |
| 12874 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { |
| 12875 | if (isc_sockaddr_equal(&zone->altxfrsource6, |
| 12876 | &zone->xfrsource6)) |
| 12877 | goto skip_master; |
| 12878 | zone->sourceaddr = zone->altxfrsource6; |
| 12879 | if (!have_xfrdscp) |
| 12880 | dscp = zone->altxfrsource6dscp; |
| 12881 | } else if (!have_xfrsource) { |
| 12882 | zone->sourceaddr = zone->xfrsource6; |
| 12883 | if (!have_xfrdscp) |
| 12884 | dscp = zone->xfrsource6dscp; |
| 12885 | } |
| 12886 | break; |
| 12887 | default: |
| 12888 | result = ISC_R_NOTIMPLEMENTED; |
| 12889 | goto cleanup; |
| 12890 | } |
| 12891 | |
| 12892 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { |
| 12893 | result = add_opt(message, udpsize, reqnsid, reqexpire); |
| 12894 | if (result != ISC_R_SUCCESS) |
| 12895 | zone_debuglog(zone, me, 1, |
| 12896 | "unable to add opt record: %s" , |
| 12897 | dns_result_totext(result)); |
| 12898 | } |
| 12899 | |
| 12900 | zone_iattach(zone, &dummy); |
| 12901 | timeout = 15; |
| 12902 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) |
| 12903 | timeout = 30; |
| 12904 | result = dns_request_createvia(zone->view->requestmgr, message, |
| 12905 | &zone->sourceaddr, &zone->masteraddr, |
| 12906 | dscp, options, key, timeout * 3, |
| 12907 | timeout, 0, zone->task, |
| 12908 | refresh_callback, zone, &zone->request); |
| 12909 | if (result != ISC_R_SUCCESS) { |
| 12910 | zone_idetach(&dummy); |
| 12911 | zone_debuglog(zone, me, 1, |
| 12912 | "dns_request_createvia4() failed: %s" , |
| 12913 | dns_result_totext(result)); |
| 12914 | goto skip_master; |
| 12915 | } else { |
| 12916 | if (isc_sockaddr_pf(&zone->masteraddr) == PF_INET) |
| 12917 | inc_stats(zone, dns_zonestatscounter_soaoutv4); |
| 12918 | else |
| 12919 | inc_stats(zone, dns_zonestatscounter_soaoutv6); |
| 12920 | } |
| 12921 | cancel = false; |
| 12922 | |
| 12923 | cleanup: |
| 12924 | if (key != NULL) |
| 12925 | dns_tsigkey_detach(&key); |
| 12926 | if (result != ISC_R_SUCCESS) |
| 12927 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 12928 | if (message != NULL) |
| 12929 | dns_message_destroy(&message); |
| 12930 | if (cancel) |
| 12931 | cancel_refresh(zone); |
| 12932 | isc_event_free(&event); |
| 12933 | UNLOCK_ZONE(zone); |
| 12934 | dns_zone_idetach(&zone); |
| 12935 | return; |
| 12936 | |
| 12937 | skip_master: |
| 12938 | if (key != NULL) |
| 12939 | dns_tsigkey_detach(&key); |
| 12940 | dns_message_destroy(&message); |
| 12941 | /* |
| 12942 | * Skip to next failed / untried master. |
| 12943 | */ |
| 12944 | do { |
| 12945 | zone->curmaster++; |
| 12946 | } while (zone->curmaster < zone->masterscnt && |
| 12947 | zone->mastersok[zone->curmaster]); |
| 12948 | if (zone->curmaster < zone->masterscnt) |
| 12949 | goto again; |
| 12950 | zone->curmaster = 0; |
| 12951 | goto cleanup; |
| 12952 | } |
| 12953 | |
| 12954 | static void |
| 12955 | ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { |
| 12956 | const char me[] = "ns_query" ; |
| 12957 | isc_result_t result; |
| 12958 | dns_message_t *message = NULL; |
| 12959 | isc_netaddr_t masterip; |
| 12960 | dns_tsigkey_t *key = NULL; |
| 12961 | dns_dbnode_t *node = NULL; |
| 12962 | int timeout; |
| 12963 | bool have_xfrsource = false, have_xfrdscp = false; |
| 12964 | bool reqnsid; |
| 12965 | uint16_t udpsize = SEND_BUFFER_SIZE; |
| 12966 | isc_dscp_t dscp = -1; |
| 12967 | |
| 12968 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 12969 | REQUIRE(LOCKED_ZONE(zone)); |
| 12970 | REQUIRE((soardataset != NULL && stub == NULL) || |
| 12971 | (soardataset == NULL && stub != NULL)); |
| 12972 | REQUIRE(stub == NULL || DNS_STUB_VALID(stub)); |
| 12973 | |
| 12974 | ENTER; |
| 12975 | |
| 12976 | if (stub == NULL) { |
| 12977 | stub = isc_mem_get(zone->mctx, sizeof(*stub)); |
| 12978 | if (stub == NULL) |
| 12979 | goto cleanup; |
| 12980 | stub->magic = STUB_MAGIC; |
| 12981 | stub->mctx = zone->mctx; |
| 12982 | stub->zone = NULL; |
| 12983 | stub->db = NULL; |
| 12984 | stub->version = NULL; |
| 12985 | |
| 12986 | /* |
| 12987 | * Attach so that the zone won't disappear from under us. |
| 12988 | */ |
| 12989 | zone_iattach(zone, &stub->zone); |
| 12990 | |
| 12991 | /* |
| 12992 | * If a db exists we will update it, otherwise we create a |
| 12993 | * new one and attach it to the zone once we have the NS |
| 12994 | * RRset and glue. |
| 12995 | */ |
| 12996 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 12997 | if (zone->db != NULL) { |
| 12998 | dns_db_attach(zone->db, &stub->db); |
| 12999 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 13000 | } else { |
| 13001 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 13002 | |
| 13003 | INSIST(zone->db_argc >= 1); |
| 13004 | result = dns_db_create(zone->mctx, zone->db_argv[0], |
| 13005 | &zone->origin, dns_dbtype_stub, |
| 13006 | zone->rdclass, |
| 13007 | zone->db_argc - 1, |
| 13008 | zone->db_argv + 1, |
| 13009 | &stub->db); |
| 13010 | if (result != ISC_R_SUCCESS) { |
| 13011 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 13012 | "refreshing stub: " |
| 13013 | "could not create " |
| 13014 | "database: %s" , |
| 13015 | dns_result_totext(result)); |
| 13016 | goto cleanup; |
| 13017 | } |
| 13018 | dns_db_settask(stub->db, zone->task); |
| 13019 | } |
| 13020 | |
| 13021 | result = dns_db_newversion(stub->db, &stub->version); |
| 13022 | if (result != ISC_R_SUCCESS) { |
| 13023 | dns_zone_log(zone, ISC_LOG_INFO, "refreshing stub: " |
| 13024 | "dns_db_newversion() failed: %s" , |
| 13025 | dns_result_totext(result)); |
| 13026 | goto cleanup; |
| 13027 | } |
| 13028 | |
| 13029 | /* |
| 13030 | * Update SOA record. |
| 13031 | */ |
| 13032 | result = dns_db_findnode(stub->db, &zone->origin, true, |
| 13033 | &node); |
| 13034 | if (result != ISC_R_SUCCESS) { |
| 13035 | dns_zone_log(zone, ISC_LOG_INFO, "refreshing stub: " |
| 13036 | "dns_db_findnode() failed: %s" , |
| 13037 | dns_result_totext(result)); |
| 13038 | goto cleanup; |
| 13039 | } |
| 13040 | |
| 13041 | result = dns_db_addrdataset(stub->db, node, stub->version, 0, |
| 13042 | soardataset, 0, NULL); |
| 13043 | dns_db_detachnode(stub->db, &node); |
| 13044 | if (result != ISC_R_SUCCESS) { |
| 13045 | dns_zone_log(zone, ISC_LOG_INFO, |
| 13046 | "refreshing stub: " |
| 13047 | "dns_db_addrdataset() failed: %s" , |
| 13048 | dns_result_totext(result)); |
| 13049 | goto cleanup; |
| 13050 | } |
| 13051 | } |
| 13052 | |
| 13053 | /* |
| 13054 | * XXX Optimisation: Create message when zone is setup and reuse. |
| 13055 | */ |
| 13056 | result = create_query(zone, dns_rdatatype_ns, &message); |
| 13057 | INSIST(result == ISC_R_SUCCESS); |
| 13058 | |
| 13059 | INSIST(zone->masterscnt > 0); |
| 13060 | INSIST(zone->curmaster < zone->masterscnt); |
| 13061 | zone->masteraddr = zone->masters[zone->curmaster]; |
| 13062 | |
| 13063 | isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); |
| 13064 | /* |
| 13065 | * First, look for a tsig key in the master statement, then |
| 13066 | * try for a server key. |
| 13067 | */ |
| 13068 | if ((zone->masterkeynames != NULL) && |
| 13069 | (zone->masterkeynames[zone->curmaster] != NULL)) { |
| 13070 | dns_view_t *view = dns_zone_getview(zone); |
| 13071 | dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; |
| 13072 | result = dns_view_gettsig(view, keyname, &key); |
| 13073 | if (result != ISC_R_SUCCESS) { |
| 13074 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 13075 | dns_name_format(keyname, namebuf, sizeof(namebuf)); |
| 13076 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 13077 | "unable to find key: %s" , namebuf); |
| 13078 | } |
| 13079 | } |
| 13080 | if (key == NULL) |
| 13081 | (void)dns_view_getpeertsig(zone->view, &masterip, &key); |
| 13082 | |
| 13083 | reqnsid = zone->view->requestnsid; |
| 13084 | if (zone->view->peers != NULL) { |
| 13085 | dns_peer_t *peer = NULL; |
| 13086 | bool edns; |
| 13087 | result = dns_peerlist_peerbyaddr(zone->view->peers, |
| 13088 | &masterip, &peer); |
| 13089 | if (result == ISC_R_SUCCESS) { |
| 13090 | result = dns_peer_getsupportedns(peer, &edns); |
| 13091 | if (result == ISC_R_SUCCESS && !edns) |
| 13092 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); |
| 13093 | result = dns_peer_gettransfersource(peer, |
| 13094 | &zone->sourceaddr); |
| 13095 | if (result == ISC_R_SUCCESS) |
| 13096 | have_xfrsource = true; |
| 13097 | result = dns_peer_gettransferdscp(peer, &dscp); |
| 13098 | if (result == ISC_R_SUCCESS && dscp != -1) |
| 13099 | have_xfrdscp = true; |
| 13100 | if (zone->view->resolver != NULL) |
| 13101 | udpsize = |
| 13102 | dns_resolver_getudpsize(zone->view->resolver); |
| 13103 | (void)dns_peer_getudpsize(peer, &udpsize); |
| 13104 | (void)dns_peer_getrequestnsid(peer, &reqnsid); |
| 13105 | } |
| 13106 | |
| 13107 | } |
| 13108 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { |
| 13109 | result = add_opt(message, udpsize, reqnsid, false); |
| 13110 | if (result != ISC_R_SUCCESS) |
| 13111 | zone_debuglog(zone, me, 1, |
| 13112 | "unable to add opt record: %s" , |
| 13113 | dns_result_totext(result)); |
| 13114 | } |
| 13115 | |
| 13116 | /* |
| 13117 | * Always use TCP so that we shouldn't truncate in additional section. |
| 13118 | */ |
| 13119 | switch (isc_sockaddr_pf(&zone->masteraddr)) { |
| 13120 | case PF_INET: |
| 13121 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { |
| 13122 | zone->sourceaddr = zone->altxfrsource4; |
| 13123 | if (!have_xfrdscp) |
| 13124 | dscp = zone->altxfrsource4dscp; |
| 13125 | } else if (!have_xfrsource) { |
| 13126 | zone->sourceaddr = zone->xfrsource4; |
| 13127 | if (!have_xfrdscp) |
| 13128 | dscp = zone->xfrsource4dscp; |
| 13129 | } |
| 13130 | break; |
| 13131 | case PF_INET6: |
| 13132 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { |
| 13133 | zone->sourceaddr = zone->altxfrsource6; |
| 13134 | if (!have_xfrdscp) |
| 13135 | dscp = zone->altxfrsource6dscp; |
| 13136 | } else if (!have_xfrsource) { |
| 13137 | zone->sourceaddr = zone->xfrsource6; |
| 13138 | if (!have_xfrdscp) |
| 13139 | dscp = zone->xfrsource6dscp; |
| 13140 | } |
| 13141 | break; |
| 13142 | default: |
| 13143 | result = ISC_R_NOTIMPLEMENTED; |
| 13144 | POST(result); |
| 13145 | goto cleanup; |
| 13146 | } |
| 13147 | timeout = 15; |
| 13148 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) |
| 13149 | timeout = 30; |
| 13150 | result = dns_request_createvia(zone->view->requestmgr, message, |
| 13151 | &zone->sourceaddr, &zone->masteraddr, |
| 13152 | dscp, DNS_REQUESTOPT_TCP, key, |
| 13153 | timeout * 3, timeout, 0, zone->task, |
| 13154 | stub_callback, stub, &zone->request); |
| 13155 | if (result != ISC_R_SUCCESS) { |
| 13156 | zone_debuglog(zone, me, 1, |
| 13157 | "dns_request_createvia() failed: %s" , |
| 13158 | dns_result_totext(result)); |
| 13159 | goto cleanup; |
| 13160 | } |
| 13161 | dns_message_destroy(&message); |
| 13162 | goto unlock; |
| 13163 | |
| 13164 | cleanup: |
| 13165 | cancel_refresh(zone); |
| 13166 | if (stub != NULL) { |
| 13167 | stub->magic = 0; |
| 13168 | if (stub->version != NULL) |
| 13169 | dns_db_closeversion(stub->db, &stub->version, |
| 13170 | false); |
| 13171 | if (stub->db != NULL) |
| 13172 | dns_db_detach(&stub->db); |
| 13173 | if (stub->zone != NULL) |
| 13174 | zone_idetach(&stub->zone); |
| 13175 | isc_mem_put(stub->mctx, stub, sizeof(*stub)); |
| 13176 | } |
| 13177 | if (message != NULL) |
| 13178 | dns_message_destroy(&message); |
| 13179 | unlock: |
| 13180 | if (key != NULL) |
| 13181 | dns_tsigkey_detach(&key); |
| 13182 | return; |
| 13183 | } |
| 13184 | |
| 13185 | /* |
| 13186 | * Handle the control event. Note that although this event causes the zone |
| 13187 | * to shut down, it is not a shutdown event in the sense of the task library. |
| 13188 | */ |
| 13189 | static void |
| 13190 | zone_shutdown(isc_task_t *task, isc_event_t *event) { |
| 13191 | dns_zone_t *zone = (dns_zone_t *) event->ev_arg; |
| 13192 | bool free_needed, linked = false; |
| 13193 | dns_zone_t *raw = NULL, *secure = NULL; |
| 13194 | |
| 13195 | UNUSED(task); |
| 13196 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13197 | INSIST(event->ev_type == DNS_EVENT_ZONECONTROL); |
| 13198 | INSIST(isc_refcount_current(&zone->erefs) == 0); |
| 13199 | |
| 13200 | zone_debuglog(zone, "zone_shutdown" , 3, "shutting down" ); |
| 13201 | |
| 13202 | /* |
| 13203 | * Stop things being restarted after we cancel them below. |
| 13204 | */ |
| 13205 | LOCK_ZONE(zone); |
| 13206 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXITING); |
| 13207 | UNLOCK_ZONE(zone); |
| 13208 | |
| 13209 | /* |
| 13210 | * If we were waiting for xfrin quota, step out of |
| 13211 | * the queue. |
| 13212 | * If there's no zone manager, we can't be waiting for the |
| 13213 | * xfrin quota |
| 13214 | */ |
| 13215 | if (zone->zmgr != NULL) { |
| 13216 | RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); |
| 13217 | if (zone->statelist == &zone->zmgr->waiting_for_xfrin) { |
| 13218 | ISC_LIST_UNLINK(zone->zmgr->waiting_for_xfrin, zone, |
| 13219 | statelink); |
| 13220 | linked = true; |
| 13221 | zone->statelist = NULL; |
| 13222 | } |
| 13223 | if (zone->statelist == &zone->zmgr->xfrin_in_progress) { |
| 13224 | ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, |
| 13225 | statelink); |
| 13226 | zone->statelist = NULL; |
| 13227 | zmgr_resume_xfrs(zone->zmgr, false); |
| 13228 | } |
| 13229 | RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); |
| 13230 | } |
| 13231 | |
| 13232 | /* |
| 13233 | * In task context, no locking required. See zone_xfrdone(). |
| 13234 | */ |
| 13235 | if (zone->xfr != NULL) |
| 13236 | dns_xfrin_shutdown(zone->xfr); |
| 13237 | |
| 13238 | /* Safe to release the zone now */ |
| 13239 | if (zone->zmgr != NULL) |
| 13240 | dns_zonemgr_releasezone(zone->zmgr, zone); |
| 13241 | |
| 13242 | LOCK_ZONE(zone); |
| 13243 | INSIST(zone != zone->raw); |
| 13244 | if (linked) { |
| 13245 | INSIST(zone->irefs > 0); |
| 13246 | zone->irefs--; |
| 13247 | } |
| 13248 | if (zone->request != NULL) { |
| 13249 | dns_request_cancel(zone->request); |
| 13250 | } |
| 13251 | |
| 13252 | if (zone->readio != NULL) |
| 13253 | zonemgr_cancelio(zone->readio); |
| 13254 | |
| 13255 | if (zone->lctx != NULL) |
| 13256 | dns_loadctx_cancel(zone->lctx); |
| 13257 | |
| 13258 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) || |
| 13259 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { |
| 13260 | if (zone->writeio != NULL) |
| 13261 | zonemgr_cancelio(zone->writeio); |
| 13262 | |
| 13263 | if (zone->dctx != NULL) |
| 13264 | dns_dumpctx_cancel(zone->dctx); |
| 13265 | } |
| 13266 | |
| 13267 | notify_cancel(zone); |
| 13268 | |
| 13269 | forward_cancel(zone); |
| 13270 | |
| 13271 | if (zone->timer != NULL) { |
| 13272 | isc_timer_detach(&zone->timer); |
| 13273 | INSIST(zone->irefs > 0); |
| 13274 | zone->irefs--; |
| 13275 | } |
| 13276 | |
| 13277 | /* |
| 13278 | * We have now canceled everything set the flag to allow exit_check() |
| 13279 | * to succeed. We must not unlock between setting this flag and |
| 13280 | * calling exit_check(). |
| 13281 | */ |
| 13282 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN); |
| 13283 | free_needed = exit_check(zone); |
| 13284 | if (inline_secure(zone)) { |
| 13285 | raw = zone->raw; |
| 13286 | zone->raw = NULL; |
| 13287 | } |
| 13288 | if (inline_raw(zone)) { |
| 13289 | secure = zone->secure; |
| 13290 | zone->secure = NULL; |
| 13291 | } |
| 13292 | UNLOCK_ZONE(zone); |
| 13293 | if (raw != NULL) |
| 13294 | dns_zone_detach(&raw); |
| 13295 | if (secure != NULL) |
| 13296 | dns_zone_idetach(&secure); |
| 13297 | if (free_needed) |
| 13298 | zone_free(zone); |
| 13299 | } |
| 13300 | |
| 13301 | static void |
| 13302 | zone_timer(isc_task_t *task, isc_event_t *event) { |
| 13303 | const char me[] = "zone_timer" ; |
| 13304 | dns_zone_t *zone = (dns_zone_t *)event->ev_arg; |
| 13305 | |
| 13306 | UNUSED(task); |
| 13307 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13308 | |
| 13309 | ENTER; |
| 13310 | |
| 13311 | zone_maintenance(zone); |
| 13312 | |
| 13313 | isc_event_free(&event); |
| 13314 | } |
| 13315 | |
| 13316 | static void |
| 13317 | zone_settimer(dns_zone_t *zone, isc_time_t *now) { |
| 13318 | const char me[] = "zone_settimer" ; |
| 13319 | isc_time_t next; |
| 13320 | isc_result_t result; |
| 13321 | |
| 13322 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13323 | ENTER; |
| 13324 | |
| 13325 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) |
| 13326 | return; |
| 13327 | |
| 13328 | isc_time_settoepoch(&next); |
| 13329 | |
| 13330 | switch (zone->type) { |
| 13331 | case dns_zone_redirect: |
| 13332 | if (zone->masters != NULL) |
| 13333 | goto treat_as_slave; |
| 13334 | /* FALLTHROUGH */ |
| 13335 | |
| 13336 | case dns_zone_master: |
| 13337 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) || |
| 13338 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY)) |
| 13339 | next = zone->notifytime; |
| 13340 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && |
| 13341 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { |
| 13342 | INSIST(!isc_time_isepoch(&zone->dumptime)); |
| 13343 | if (isc_time_isepoch(&next) || |
| 13344 | isc_time_compare(&zone->dumptime, &next) < 0) |
| 13345 | next = zone->dumptime; |
| 13346 | } |
| 13347 | if (zone->type == dns_zone_redirect) |
| 13348 | break; |
| 13349 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING) && |
| 13350 | !isc_time_isepoch(&zone->refreshkeytime)) { |
| 13351 | if (isc_time_isepoch(&next) || |
| 13352 | isc_time_compare(&zone->refreshkeytime, &next) < 0) |
| 13353 | next = zone->refreshkeytime; |
| 13354 | } |
| 13355 | if (!isc_time_isepoch(&zone->resigntime)) { |
| 13356 | if (isc_time_isepoch(&next) || |
| 13357 | isc_time_compare(&zone->resigntime, &next) < 0) |
| 13358 | next = zone->resigntime; |
| 13359 | } |
| 13360 | if (!isc_time_isepoch(&zone->keywarntime)) { |
| 13361 | if (isc_time_isepoch(&next) || |
| 13362 | isc_time_compare(&zone->keywarntime, &next) < 0) |
| 13363 | next = zone->keywarntime; |
| 13364 | } |
| 13365 | if (!isc_time_isepoch(&zone->signingtime)) { |
| 13366 | if (isc_time_isepoch(&next) || |
| 13367 | isc_time_compare(&zone->signingtime, &next) < 0) |
| 13368 | next = zone->signingtime; |
| 13369 | } |
| 13370 | if (!isc_time_isepoch(&zone->nsec3chaintime)) { |
| 13371 | if (isc_time_isepoch(&next) || |
| 13372 | isc_time_compare(&zone->nsec3chaintime, &next) < 0) |
| 13373 | next = zone->nsec3chaintime; |
| 13374 | } |
| 13375 | break; |
| 13376 | |
| 13377 | case dns_zone_slave: |
| 13378 | case dns_zone_mirror: |
| 13379 | treat_as_slave: |
| 13380 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) || |
| 13381 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY)) |
| 13382 | next = zone->notifytime; |
| 13383 | /* FALLTHROUGH */ |
| 13384 | |
| 13385 | case dns_zone_stub: |
| 13386 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH) && |
| 13387 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOMASTERS) && |
| 13388 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH) && |
| 13389 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING) && |
| 13390 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING) && |
| 13391 | !isc_time_isepoch(&zone->refreshtime) && |
| 13392 | (isc_time_isepoch(&next) || |
| 13393 | isc_time_compare(&zone->refreshtime, &next) < 0)) |
| 13394 | next = zone->refreshtime; |
| 13395 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && |
| 13396 | !isc_time_isepoch(&zone->expiretime)) { |
| 13397 | if (isc_time_isepoch(&next) || |
| 13398 | isc_time_compare(&zone->expiretime, &next) < 0) |
| 13399 | next = zone->expiretime; |
| 13400 | } |
| 13401 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && |
| 13402 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { |
| 13403 | INSIST(!isc_time_isepoch(&zone->dumptime)); |
| 13404 | if (isc_time_isepoch(&next) || |
| 13405 | isc_time_compare(&zone->dumptime, &next) < 0) |
| 13406 | next = zone->dumptime; |
| 13407 | } |
| 13408 | break; |
| 13409 | |
| 13410 | case dns_zone_key: |
| 13411 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && |
| 13412 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { |
| 13413 | INSIST(!isc_time_isepoch(&zone->dumptime)); |
| 13414 | if (isc_time_isepoch(&next) || |
| 13415 | isc_time_compare(&zone->dumptime, &next) < 0) |
| 13416 | next = zone->dumptime; |
| 13417 | } |
| 13418 | if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) { |
| 13419 | if (isc_time_isepoch(&next) || |
| 13420 | (!isc_time_isepoch(&zone->refreshkeytime) && |
| 13421 | isc_time_compare(&zone->refreshkeytime, &next) < 0)) |
| 13422 | next = zone->refreshkeytime; |
| 13423 | } |
| 13424 | break; |
| 13425 | |
| 13426 | default: |
| 13427 | break; |
| 13428 | } |
| 13429 | |
| 13430 | if (isc_time_isepoch(&next)) { |
| 13431 | zone_debuglog(zone, me, 10, "settimer inactive" ); |
| 13432 | result = isc_timer_reset(zone->timer, isc_timertype_inactive, |
| 13433 | NULL, NULL, true); |
| 13434 | if (result != ISC_R_SUCCESS) |
| 13435 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 13436 | "could not deactivate zone timer: %s" , |
| 13437 | isc_result_totext(result)); |
| 13438 | } else { |
| 13439 | if (isc_time_compare(&next, now) <= 0) |
| 13440 | next = *now; |
| 13441 | result = isc_timer_reset(zone->timer, isc_timertype_once, |
| 13442 | &next, NULL, true); |
| 13443 | if (result != ISC_R_SUCCESS) |
| 13444 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 13445 | "could not reset zone timer: %s" , |
| 13446 | isc_result_totext(result)); |
| 13447 | } |
| 13448 | } |
| 13449 | |
| 13450 | static void |
| 13451 | cancel_refresh(dns_zone_t *zone) { |
| 13452 | const char me[] = "cancel_refresh" ; |
| 13453 | isc_time_t now; |
| 13454 | |
| 13455 | /* |
| 13456 | * 'zone' locked by caller. |
| 13457 | */ |
| 13458 | |
| 13459 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13460 | REQUIRE(LOCKED_ZONE(zone)); |
| 13461 | |
| 13462 | ENTER; |
| 13463 | |
| 13464 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 13465 | TIME_NOW(&now); |
| 13466 | zone_settimer(zone, &now); |
| 13467 | } |
| 13468 | |
| 13469 | static isc_result_t |
| 13470 | notify_createmessage(dns_zone_t *zone, unsigned int flags, |
| 13471 | dns_message_t **messagep) |
| 13472 | { |
| 13473 | dns_db_t *zonedb = NULL; |
| 13474 | dns_dbnode_t *node = NULL; |
| 13475 | dns_dbversion_t *version = NULL; |
| 13476 | dns_message_t *message = NULL; |
| 13477 | dns_rdataset_t rdataset; |
| 13478 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 13479 | |
| 13480 | dns_name_t *tempname = NULL; |
| 13481 | dns_rdata_t *temprdata = NULL; |
| 13482 | dns_rdatalist_t *temprdatalist = NULL; |
| 13483 | dns_rdataset_t *temprdataset = NULL; |
| 13484 | |
| 13485 | isc_result_t result; |
| 13486 | isc_region_t r; |
| 13487 | isc_buffer_t *b = NULL; |
| 13488 | |
| 13489 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13490 | REQUIRE(messagep != NULL && *messagep == NULL); |
| 13491 | |
| 13492 | result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, |
| 13493 | &message); |
| 13494 | if (result != ISC_R_SUCCESS) |
| 13495 | return (result); |
| 13496 | |
| 13497 | message->opcode = dns_opcode_notify; |
| 13498 | message->flags |= DNS_MESSAGEFLAG_AA; |
| 13499 | message->rdclass = zone->rdclass; |
| 13500 | |
| 13501 | result = dns_message_gettempname(message, &tempname); |
| 13502 | if (result != ISC_R_SUCCESS) |
| 13503 | goto cleanup; |
| 13504 | |
| 13505 | result = dns_message_gettemprdataset(message, &temprdataset); |
| 13506 | if (result != ISC_R_SUCCESS) |
| 13507 | goto cleanup; |
| 13508 | |
| 13509 | /* |
| 13510 | * Make question. |
| 13511 | */ |
| 13512 | dns_name_init(tempname, NULL); |
| 13513 | dns_name_clone(&zone->origin, tempname); |
| 13514 | dns_rdataset_makequestion(temprdataset, zone->rdclass, |
| 13515 | dns_rdatatype_soa); |
| 13516 | ISC_LIST_APPEND(tempname->list, temprdataset, link); |
| 13517 | dns_message_addname(message, tempname, DNS_SECTION_QUESTION); |
| 13518 | tempname = NULL; |
| 13519 | temprdataset = NULL; |
| 13520 | |
| 13521 | if ((flags & DNS_NOTIFY_NOSOA) != 0) |
| 13522 | goto done; |
| 13523 | |
| 13524 | result = dns_message_gettempname(message, &tempname); |
| 13525 | if (result != ISC_R_SUCCESS) |
| 13526 | goto soa_cleanup; |
| 13527 | result = dns_message_gettemprdata(message, &temprdata); |
| 13528 | if (result != ISC_R_SUCCESS) |
| 13529 | goto soa_cleanup; |
| 13530 | result = dns_message_gettemprdataset(message, &temprdataset); |
| 13531 | if (result != ISC_R_SUCCESS) |
| 13532 | goto soa_cleanup; |
| 13533 | result = dns_message_gettemprdatalist(message, &temprdatalist); |
| 13534 | if (result != ISC_R_SUCCESS) |
| 13535 | goto soa_cleanup; |
| 13536 | |
| 13537 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 13538 | INSIST(zone->db != NULL); /* XXXJT: is this assumption correct? */ |
| 13539 | dns_db_attach(zone->db, &zonedb); |
| 13540 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 13541 | |
| 13542 | dns_name_init(tempname, NULL); |
| 13543 | dns_name_clone(&zone->origin, tempname); |
| 13544 | dns_db_currentversion(zonedb, &version); |
| 13545 | result = dns_db_findnode(zonedb, tempname, false, &node); |
| 13546 | if (result != ISC_R_SUCCESS) |
| 13547 | goto soa_cleanup; |
| 13548 | |
| 13549 | dns_rdataset_init(&rdataset); |
| 13550 | result = dns_db_findrdataset(zonedb, node, version, |
| 13551 | dns_rdatatype_soa, |
| 13552 | dns_rdatatype_none, 0, &rdataset, |
| 13553 | NULL); |
| 13554 | if (result != ISC_R_SUCCESS) |
| 13555 | goto soa_cleanup; |
| 13556 | result = dns_rdataset_first(&rdataset); |
| 13557 | if (result != ISC_R_SUCCESS) |
| 13558 | goto soa_cleanup; |
| 13559 | dns_rdataset_current(&rdataset, &rdata); |
| 13560 | dns_rdata_toregion(&rdata, &r); |
| 13561 | result = isc_buffer_allocate(zone->mctx, &b, r.length); |
| 13562 | if (result != ISC_R_SUCCESS) |
| 13563 | goto soa_cleanup; |
| 13564 | isc_buffer_putmem(b, r.base, r.length); |
| 13565 | isc_buffer_usedregion(b, &r); |
| 13566 | dns_rdata_init(temprdata); |
| 13567 | dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r); |
| 13568 | dns_message_takebuffer(message, &b); |
| 13569 | result = dns_rdataset_next(&rdataset); |
| 13570 | dns_rdataset_disassociate(&rdataset); |
| 13571 | if (result != ISC_R_NOMORE) |
| 13572 | goto soa_cleanup; |
| 13573 | temprdatalist->rdclass = rdata.rdclass; |
| 13574 | temprdatalist->type = rdata.type; |
| 13575 | temprdatalist->ttl = rdataset.ttl; |
| 13576 | ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link); |
| 13577 | |
| 13578 | result = dns_rdatalist_tordataset(temprdatalist, temprdataset); |
| 13579 | if (result != ISC_R_SUCCESS) |
| 13580 | goto soa_cleanup; |
| 13581 | |
| 13582 | ISC_LIST_APPEND(tempname->list, temprdataset, link); |
| 13583 | dns_message_addname(message, tempname, DNS_SECTION_ANSWER); |
| 13584 | temprdatalist = NULL; |
| 13585 | temprdataset = NULL; |
| 13586 | temprdata = NULL; |
| 13587 | tempname = NULL; |
| 13588 | |
| 13589 | soa_cleanup: |
| 13590 | if (node != NULL) |
| 13591 | dns_db_detachnode(zonedb, &node); |
| 13592 | if (version != NULL) |
| 13593 | dns_db_closeversion(zonedb, &version, false); |
| 13594 | if (zonedb != NULL) |
| 13595 | dns_db_detach(&zonedb); |
| 13596 | if (tempname != NULL) |
| 13597 | dns_message_puttempname(message, &tempname); |
| 13598 | if (temprdata != NULL) |
| 13599 | dns_message_puttemprdata(message, &temprdata); |
| 13600 | if (temprdataset != NULL) |
| 13601 | dns_message_puttemprdataset(message, &temprdataset); |
| 13602 | if (temprdatalist != NULL) |
| 13603 | dns_message_puttemprdatalist(message, &temprdatalist); |
| 13604 | |
| 13605 | done: |
| 13606 | *messagep = message; |
| 13607 | return (ISC_R_SUCCESS); |
| 13608 | |
| 13609 | cleanup: |
| 13610 | if (tempname != NULL) |
| 13611 | dns_message_puttempname(message, &tempname); |
| 13612 | if (temprdataset != NULL) |
| 13613 | dns_message_puttemprdataset(message, &temprdataset); |
| 13614 | dns_message_destroy(&message); |
| 13615 | return (result); |
| 13616 | } |
| 13617 | |
| 13618 | isc_result_t |
| 13619 | dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, |
| 13620 | isc_sockaddr_t *to, dns_message_t *msg) |
| 13621 | { |
| 13622 | unsigned int i; |
| 13623 | dns_rdata_soa_t soa; |
| 13624 | dns_rdataset_t *rdataset = NULL; |
| 13625 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 13626 | isc_result_t result; |
| 13627 | char fromtext[ISC_SOCKADDR_FORMATSIZE]; |
| 13628 | int match = 0; |
| 13629 | isc_netaddr_t netaddr; |
| 13630 | uint32_t serial = 0; |
| 13631 | bool have_serial = false; |
| 13632 | dns_tsigkey_t *tsigkey; |
| 13633 | dns_name_t *tsig; |
| 13634 | |
| 13635 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13636 | |
| 13637 | /* |
| 13638 | * If type != T_SOA return DNS_R_NOTIMP. We don't yet support |
| 13639 | * ROLLOVER. |
| 13640 | * |
| 13641 | * SOA: RFC1996 |
| 13642 | * Check that 'from' is a valid notify source, (zone->masters). |
| 13643 | * Return DNS_R_REFUSED if not. |
| 13644 | * |
| 13645 | * If the notify message contains a serial number check it |
| 13646 | * against the zones serial and return if <= current serial |
| 13647 | * |
| 13648 | * If a refresh check is progress, if so just record the |
| 13649 | * fact we received a NOTIFY and from where and return. |
| 13650 | * We will perform a new refresh check when the current one |
| 13651 | * completes. Return ISC_R_SUCCESS. |
| 13652 | * |
| 13653 | * Otherwise initiate a refresh check using 'from' as the |
| 13654 | * first address to check. Return ISC_R_SUCCESS. |
| 13655 | */ |
| 13656 | |
| 13657 | isc_sockaddr_format(from, fromtext, sizeof(fromtext)); |
| 13658 | |
| 13659 | /* |
| 13660 | * Notify messages are processed by the raw zone. |
| 13661 | */ |
| 13662 | LOCK_ZONE(zone); |
| 13663 | INSIST(zone != zone->raw); |
| 13664 | if (inline_secure(zone)) { |
| 13665 | result = dns_zone_notifyreceive(zone->raw, from, to, msg); |
| 13666 | UNLOCK_ZONE(zone); |
| 13667 | return (result); |
| 13668 | } |
| 13669 | /* |
| 13670 | * We only handle NOTIFY (SOA) at the present. |
| 13671 | */ |
| 13672 | if (isc_sockaddr_pf(from) == PF_INET) |
| 13673 | inc_stats(zone, dns_zonestatscounter_notifyinv4); |
| 13674 | else |
| 13675 | inc_stats(zone, dns_zonestatscounter_notifyinv6); |
| 13676 | if (msg->counts[DNS_SECTION_QUESTION] == 0 || |
| 13677 | dns_message_findname(msg, DNS_SECTION_QUESTION, &zone->origin, |
| 13678 | dns_rdatatype_soa, dns_rdatatype_none, |
| 13679 | NULL, NULL) != ISC_R_SUCCESS) { |
| 13680 | UNLOCK_ZONE(zone); |
| 13681 | if (msg->counts[DNS_SECTION_QUESTION] == 0) { |
| 13682 | dns_zone_log(zone, ISC_LOG_NOTICE, |
| 13683 | "NOTIFY with no " |
| 13684 | "question section from: %s" , fromtext); |
| 13685 | return (DNS_R_FORMERR); |
| 13686 | } |
| 13687 | dns_zone_log(zone, ISC_LOG_NOTICE, |
| 13688 | "NOTIFY zone does not match" ); |
| 13689 | return (DNS_R_NOTIMP); |
| 13690 | } |
| 13691 | |
| 13692 | /* |
| 13693 | * If we are a master zone just succeed. |
| 13694 | */ |
| 13695 | if (zone->type == dns_zone_master) { |
| 13696 | UNLOCK_ZONE(zone); |
| 13697 | return (ISC_R_SUCCESS); |
| 13698 | } |
| 13699 | |
| 13700 | isc_netaddr_fromsockaddr(&netaddr, from); |
| 13701 | for (i = 0; i < zone->masterscnt; i++) { |
| 13702 | if (isc_sockaddr_eqaddr(from, &zone->masters[i])) |
| 13703 | break; |
| 13704 | if (zone->view->aclenv.match_mapped && |
| 13705 | IN6_IS_ADDR_V4MAPPED(&from->type.sin6.sin6_addr) && |
| 13706 | isc_sockaddr_pf(&zone->masters[i]) == AF_INET) { |
| 13707 | isc_netaddr_t na1, na2; |
| 13708 | isc_netaddr_fromv4mapped(&na1, &netaddr); |
| 13709 | isc_netaddr_fromsockaddr(&na2, &zone->masters[i]); |
| 13710 | if (isc_netaddr_equal(&na1, &na2)) |
| 13711 | break; |
| 13712 | } |
| 13713 | } |
| 13714 | |
| 13715 | /* |
| 13716 | * Accept notify requests from non masters if they are on |
| 13717 | * 'zone->notify_acl'. |
| 13718 | */ |
| 13719 | tsigkey = dns_message_gettsigkey(msg); |
| 13720 | tsig = dns_tsigkey_identity(tsigkey); |
| 13721 | if (i >= zone->masterscnt && zone->notify_acl != NULL && |
| 13722 | (dns_acl_match(&netaddr, tsig, zone->notify_acl, |
| 13723 | &zone->view->aclenv, &match, |
| 13724 | NULL) == ISC_R_SUCCESS) && |
| 13725 | match > 0) |
| 13726 | { |
| 13727 | /* Accept notify. */ |
| 13728 | } else if (i >= zone->masterscnt) { |
| 13729 | UNLOCK_ZONE(zone); |
| 13730 | dns_zone_log(zone, ISC_LOG_INFO, |
| 13731 | "refused notify from non-master: %s" , fromtext); |
| 13732 | inc_stats(zone, dns_zonestatscounter_notifyrej); |
| 13733 | return (DNS_R_REFUSED); |
| 13734 | } |
| 13735 | |
| 13736 | /* |
| 13737 | * If the zone is loaded and there are answers check the serial |
| 13738 | * to see if we need to do a refresh. Do not worry about this |
| 13739 | * check if we are a dialup zone as we use the notify request |
| 13740 | * to trigger a refresh check. |
| 13741 | */ |
| 13742 | if (msg->counts[DNS_SECTION_ANSWER] > 0 && |
| 13743 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && |
| 13744 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH)) { |
| 13745 | result = dns_message_findname(msg, DNS_SECTION_ANSWER, |
| 13746 | &zone->origin, |
| 13747 | dns_rdatatype_soa, |
| 13748 | dns_rdatatype_none, NULL, |
| 13749 | &rdataset); |
| 13750 | if (result == ISC_R_SUCCESS) |
| 13751 | result = dns_rdataset_first(rdataset); |
| 13752 | if (result == ISC_R_SUCCESS) { |
| 13753 | uint32_t oldserial; |
| 13754 | unsigned int soacount; |
| 13755 | |
| 13756 | dns_rdataset_current(rdataset, &rdata); |
| 13757 | result = dns_rdata_tostruct(&rdata, &soa, NULL); |
| 13758 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 13759 | serial = soa.serial; |
| 13760 | have_serial = true; |
| 13761 | /* |
| 13762 | * The following should safely be performed without DB |
| 13763 | * lock and succeed in this context. |
| 13764 | */ |
| 13765 | result = zone_get_from_db(zone, zone->db, NULL, |
| 13766 | &soacount, &oldserial, NULL, |
| 13767 | NULL, NULL, NULL, NULL); |
| 13768 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 13769 | RUNTIME_CHECK(soacount > 0U); |
| 13770 | if (isc_serial_le(serial, oldserial)) { |
| 13771 | dns_zone_log(zone, |
| 13772 | ISC_LOG_INFO, |
| 13773 | "notify from %s: " |
| 13774 | "zone is up to date" , |
| 13775 | fromtext); |
| 13776 | UNLOCK_ZONE(zone); |
| 13777 | return (ISC_R_SUCCESS); |
| 13778 | } |
| 13779 | } |
| 13780 | } |
| 13781 | |
| 13782 | /* |
| 13783 | * If we got this far and there was a refresh in progress just |
| 13784 | * let it complete. Record where we got the notify from so we |
| 13785 | * can perform a refresh check when the current one completes |
| 13786 | */ |
| 13787 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) { |
| 13788 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); |
| 13789 | zone->notifyfrom = *from; |
| 13790 | UNLOCK_ZONE(zone); |
| 13791 | if (have_serial) |
| 13792 | dns_zone_log(zone, ISC_LOG_INFO, |
| 13793 | "notify from %s: serial %u: refresh in " |
| 13794 | "progress, refresh check queued" , |
| 13795 | fromtext, serial); |
| 13796 | else |
| 13797 | dns_zone_log(zone, ISC_LOG_INFO, |
| 13798 | "notify from %s: refresh in progress, " |
| 13799 | "refresh check queued" , fromtext); |
| 13800 | return (ISC_R_SUCCESS); |
| 13801 | } |
| 13802 | if (have_serial) |
| 13803 | dns_zone_log(zone, ISC_LOG_INFO, "notify from %s: serial %u" , |
| 13804 | fromtext, serial); |
| 13805 | else |
| 13806 | dns_zone_log(zone, ISC_LOG_INFO, "notify from %s: no serial" , |
| 13807 | fromtext); |
| 13808 | zone->notifyfrom = *from; |
| 13809 | UNLOCK_ZONE(zone); |
| 13810 | |
| 13811 | if (to != NULL) { |
| 13812 | dns_zonemgr_unreachabledel(zone->zmgr, from, to); |
| 13813 | } |
| 13814 | dns_zone_refresh(zone); |
| 13815 | return (ISC_R_SUCCESS); |
| 13816 | } |
| 13817 | |
| 13818 | void |
| 13819 | dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl) { |
| 13820 | |
| 13821 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13822 | |
| 13823 | LOCK_ZONE(zone); |
| 13824 | if (zone->notify_acl != NULL) |
| 13825 | dns_acl_detach(&zone->notify_acl); |
| 13826 | dns_acl_attach(acl, &zone->notify_acl); |
| 13827 | UNLOCK_ZONE(zone); |
| 13828 | } |
| 13829 | |
| 13830 | void |
| 13831 | dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl) { |
| 13832 | |
| 13833 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13834 | |
| 13835 | LOCK_ZONE(zone); |
| 13836 | if (zone->query_acl != NULL) |
| 13837 | dns_acl_detach(&zone->query_acl); |
| 13838 | dns_acl_attach(acl, &zone->query_acl); |
| 13839 | UNLOCK_ZONE(zone); |
| 13840 | } |
| 13841 | |
| 13842 | void |
| 13843 | dns_zone_setqueryonacl(dns_zone_t *zone, dns_acl_t *acl) { |
| 13844 | |
| 13845 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13846 | |
| 13847 | LOCK_ZONE(zone); |
| 13848 | if (zone->queryon_acl != NULL) |
| 13849 | dns_acl_detach(&zone->queryon_acl); |
| 13850 | dns_acl_attach(acl, &zone->queryon_acl); |
| 13851 | UNLOCK_ZONE(zone); |
| 13852 | } |
| 13853 | |
| 13854 | void |
| 13855 | dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl) { |
| 13856 | |
| 13857 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13858 | |
| 13859 | LOCK_ZONE(zone); |
| 13860 | if (zone->update_acl != NULL) |
| 13861 | dns_acl_detach(&zone->update_acl); |
| 13862 | dns_acl_attach(acl, &zone->update_acl); |
| 13863 | UNLOCK_ZONE(zone); |
| 13864 | } |
| 13865 | |
| 13866 | void |
| 13867 | dns_zone_setforwardacl(dns_zone_t *zone, dns_acl_t *acl) { |
| 13868 | |
| 13869 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13870 | |
| 13871 | LOCK_ZONE(zone); |
| 13872 | if (zone->forward_acl != NULL) |
| 13873 | dns_acl_detach(&zone->forward_acl); |
| 13874 | dns_acl_attach(acl, &zone->forward_acl); |
| 13875 | UNLOCK_ZONE(zone); |
| 13876 | } |
| 13877 | |
| 13878 | void |
| 13879 | dns_zone_setxfracl(dns_zone_t *zone, dns_acl_t *acl) { |
| 13880 | |
| 13881 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13882 | |
| 13883 | LOCK_ZONE(zone); |
| 13884 | if (zone->xfr_acl != NULL) |
| 13885 | dns_acl_detach(&zone->xfr_acl); |
| 13886 | dns_acl_attach(acl, &zone->xfr_acl); |
| 13887 | UNLOCK_ZONE(zone); |
| 13888 | } |
| 13889 | |
| 13890 | dns_acl_t * |
| 13891 | dns_zone_getnotifyacl(dns_zone_t *zone) { |
| 13892 | |
| 13893 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13894 | |
| 13895 | return (zone->notify_acl); |
| 13896 | } |
| 13897 | |
| 13898 | dns_acl_t * |
| 13899 | dns_zone_getqueryacl(dns_zone_t *zone) { |
| 13900 | |
| 13901 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13902 | |
| 13903 | return (zone->query_acl); |
| 13904 | } |
| 13905 | |
| 13906 | dns_acl_t * |
| 13907 | dns_zone_getqueryonacl(dns_zone_t *zone) { |
| 13908 | |
| 13909 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13910 | |
| 13911 | return (zone->queryon_acl); |
| 13912 | } |
| 13913 | |
| 13914 | dns_acl_t * |
| 13915 | dns_zone_getupdateacl(dns_zone_t *zone) { |
| 13916 | |
| 13917 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13918 | |
| 13919 | return (zone->update_acl); |
| 13920 | } |
| 13921 | |
| 13922 | dns_acl_t * |
| 13923 | dns_zone_getforwardacl(dns_zone_t *zone) { |
| 13924 | |
| 13925 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13926 | |
| 13927 | return (zone->forward_acl); |
| 13928 | } |
| 13929 | |
| 13930 | dns_acl_t * |
| 13931 | dns_zone_getxfracl(dns_zone_t *zone) { |
| 13932 | |
| 13933 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13934 | |
| 13935 | return (zone->xfr_acl); |
| 13936 | } |
| 13937 | |
| 13938 | void |
| 13939 | dns_zone_clearupdateacl(dns_zone_t *zone) { |
| 13940 | |
| 13941 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13942 | |
| 13943 | LOCK_ZONE(zone); |
| 13944 | if (zone->update_acl != NULL) |
| 13945 | dns_acl_detach(&zone->update_acl); |
| 13946 | UNLOCK_ZONE(zone); |
| 13947 | } |
| 13948 | |
| 13949 | void |
| 13950 | dns_zone_clearforwardacl(dns_zone_t *zone) { |
| 13951 | |
| 13952 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13953 | |
| 13954 | LOCK_ZONE(zone); |
| 13955 | if (zone->forward_acl != NULL) |
| 13956 | dns_acl_detach(&zone->forward_acl); |
| 13957 | UNLOCK_ZONE(zone); |
| 13958 | } |
| 13959 | |
| 13960 | void |
| 13961 | dns_zone_clearnotifyacl(dns_zone_t *zone) { |
| 13962 | |
| 13963 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13964 | |
| 13965 | LOCK_ZONE(zone); |
| 13966 | if (zone->notify_acl != NULL) |
| 13967 | dns_acl_detach(&zone->notify_acl); |
| 13968 | UNLOCK_ZONE(zone); |
| 13969 | } |
| 13970 | |
| 13971 | void |
| 13972 | dns_zone_clearqueryacl(dns_zone_t *zone) { |
| 13973 | |
| 13974 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13975 | |
| 13976 | LOCK_ZONE(zone); |
| 13977 | if (zone->query_acl != NULL) |
| 13978 | dns_acl_detach(&zone->query_acl); |
| 13979 | UNLOCK_ZONE(zone); |
| 13980 | } |
| 13981 | |
| 13982 | void |
| 13983 | dns_zone_clearqueryonacl(dns_zone_t *zone) { |
| 13984 | |
| 13985 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13986 | |
| 13987 | LOCK_ZONE(zone); |
| 13988 | if (zone->queryon_acl != NULL) |
| 13989 | dns_acl_detach(&zone->queryon_acl); |
| 13990 | UNLOCK_ZONE(zone); |
| 13991 | } |
| 13992 | |
| 13993 | void |
| 13994 | dns_zone_clearxfracl(dns_zone_t *zone) { |
| 13995 | |
| 13996 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 13997 | |
| 13998 | LOCK_ZONE(zone); |
| 13999 | if (zone->xfr_acl != NULL) |
| 14000 | dns_acl_detach(&zone->xfr_acl); |
| 14001 | UNLOCK_ZONE(zone); |
| 14002 | } |
| 14003 | |
| 14004 | bool |
| 14005 | dns_zone_getupdatedisabled(dns_zone_t *zone) { |
| 14006 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14007 | return (zone->update_disabled); |
| 14008 | |
| 14009 | } |
| 14010 | |
| 14011 | void |
| 14012 | dns_zone_setupdatedisabled(dns_zone_t *zone, bool state) { |
| 14013 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14014 | zone->update_disabled = state; |
| 14015 | } |
| 14016 | |
| 14017 | bool |
| 14018 | dns_zone_getzeronosoattl(dns_zone_t *zone) { |
| 14019 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14020 | return (zone->zero_no_soa_ttl); |
| 14021 | |
| 14022 | } |
| 14023 | |
| 14024 | void |
| 14025 | dns_zone_setzeronosoattl(dns_zone_t *zone, bool state) { |
| 14026 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14027 | zone->zero_no_soa_ttl = state; |
| 14028 | } |
| 14029 | |
| 14030 | void |
| 14031 | dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity) { |
| 14032 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14033 | |
| 14034 | zone->check_names = severity; |
| 14035 | } |
| 14036 | |
| 14037 | dns_severity_t |
| 14038 | dns_zone_getchecknames(dns_zone_t *zone) { |
| 14039 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14040 | |
| 14041 | return (zone->check_names); |
| 14042 | } |
| 14043 | |
| 14044 | void |
| 14045 | dns_zone_setjournalsize(dns_zone_t *zone, int32_t size) { |
| 14046 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14047 | |
| 14048 | zone->journalsize = size; |
| 14049 | } |
| 14050 | |
| 14051 | int32_t |
| 14052 | dns_zone_getjournalsize(dns_zone_t *zone) { |
| 14053 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14054 | |
| 14055 | return (zone->journalsize); |
| 14056 | } |
| 14057 | |
| 14058 | static void |
| 14059 | zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) { |
| 14060 | isc_result_t result = ISC_R_FAILURE; |
| 14061 | isc_buffer_t buffer; |
| 14062 | |
| 14063 | REQUIRE(buf != NULL); |
| 14064 | REQUIRE(length > 1U); |
| 14065 | |
| 14066 | /* |
| 14067 | * Leave space for terminating '\0'. |
| 14068 | */ |
| 14069 | isc_buffer_init(&buffer, buf, (unsigned int)length - 1); |
| 14070 | if (zone->type != dns_zone_redirect && zone->type != dns_zone_key) { |
| 14071 | if (dns_name_dynamic(&zone->origin)) |
| 14072 | result = dns_name_totext(&zone->origin, true, &buffer); |
| 14073 | if (result != ISC_R_SUCCESS && |
| 14074 | isc_buffer_availablelength(&buffer) >= (sizeof("<UNKNOWN>" ) - 1)) |
| 14075 | isc_buffer_putstr(&buffer, "<UNKNOWN>" ); |
| 14076 | |
| 14077 | if (isc_buffer_availablelength(&buffer) > 0) |
| 14078 | isc_buffer_putstr(&buffer, "/" ); |
| 14079 | (void)dns_rdataclass_totext(zone->rdclass, &buffer); |
| 14080 | } |
| 14081 | |
| 14082 | if (zone->view != NULL && strcmp(zone->view->name, "_bind" ) != 0 && |
| 14083 | strcmp(zone->view->name, "_default" ) != 0 && |
| 14084 | strlen(zone->view->name) < isc_buffer_availablelength(&buffer)) { |
| 14085 | isc_buffer_putstr(&buffer, "/" ); |
| 14086 | isc_buffer_putstr(&buffer, zone->view->name); |
| 14087 | } |
| 14088 | if (inline_secure(zone) && 9U < isc_buffer_availablelength(&buffer)) |
| 14089 | isc_buffer_putstr(&buffer, " (signed)" ); |
| 14090 | if (inline_raw(zone) && 11U < isc_buffer_availablelength(&buffer)) |
| 14091 | isc_buffer_putstr(&buffer, " (unsigned)" ); |
| 14092 | |
| 14093 | buf[isc_buffer_usedlength(&buffer)] = '\0'; |
| 14094 | } |
| 14095 | |
| 14096 | static void |
| 14097 | zone_name_tostr(dns_zone_t *zone, char *buf, size_t length) { |
| 14098 | isc_result_t result = ISC_R_FAILURE; |
| 14099 | isc_buffer_t buffer; |
| 14100 | |
| 14101 | REQUIRE(buf != NULL); |
| 14102 | REQUIRE(length > 1U); |
| 14103 | |
| 14104 | /* |
| 14105 | * Leave space for terminating '\0'. |
| 14106 | */ |
| 14107 | isc_buffer_init(&buffer, buf, (unsigned int)length - 1); |
| 14108 | if (dns_name_dynamic(&zone->origin)) |
| 14109 | result = dns_name_totext(&zone->origin, true, &buffer); |
| 14110 | if (result != ISC_R_SUCCESS && |
| 14111 | isc_buffer_availablelength(&buffer) >= (sizeof("<UNKNOWN>" ) - 1)) |
| 14112 | isc_buffer_putstr(&buffer, "<UNKNOWN>" ); |
| 14113 | |
| 14114 | buf[isc_buffer_usedlength(&buffer)] = '\0'; |
| 14115 | } |
| 14116 | |
| 14117 | static void |
| 14118 | zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length) { |
| 14119 | isc_buffer_t buffer; |
| 14120 | |
| 14121 | REQUIRE(buf != NULL); |
| 14122 | REQUIRE(length > 1U); |
| 14123 | |
| 14124 | /* |
| 14125 | * Leave space for terminating '\0'. |
| 14126 | */ |
| 14127 | isc_buffer_init(&buffer, buf, (unsigned int)length - 1); |
| 14128 | (void)dns_rdataclass_totext(zone->rdclass, &buffer); |
| 14129 | |
| 14130 | buf[isc_buffer_usedlength(&buffer)] = '\0'; |
| 14131 | } |
| 14132 | |
| 14133 | static void |
| 14134 | zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length) { |
| 14135 | isc_buffer_t buffer; |
| 14136 | |
| 14137 | REQUIRE(buf != NULL); |
| 14138 | REQUIRE(length > 1U); |
| 14139 | |
| 14140 | |
| 14141 | /* |
| 14142 | * Leave space for terminating '\0'. |
| 14143 | */ |
| 14144 | isc_buffer_init(&buffer, buf, (unsigned int)length - 1); |
| 14145 | |
| 14146 | if (zone->view == NULL) { |
| 14147 | isc_buffer_putstr(&buffer, "_none" ); |
| 14148 | } else if (strlen(zone->view->name) |
| 14149 | < isc_buffer_availablelength(&buffer)) { |
| 14150 | isc_buffer_putstr(&buffer, zone->view->name); |
| 14151 | } else { |
| 14152 | isc_buffer_putstr(&buffer, "_toolong" ); |
| 14153 | } |
| 14154 | |
| 14155 | buf[isc_buffer_usedlength(&buffer)] = '\0'; |
| 14156 | } |
| 14157 | |
| 14158 | void |
| 14159 | dns_zone_name(dns_zone_t *zone, char *buf, size_t length) { |
| 14160 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14161 | REQUIRE(buf != NULL); |
| 14162 | zone_namerd_tostr(zone, buf, length); |
| 14163 | } |
| 14164 | |
| 14165 | void |
| 14166 | dns_zone_nameonly(dns_zone_t *zone, char *buf, size_t length) { |
| 14167 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14168 | REQUIRE(buf != NULL); |
| 14169 | zone_name_tostr(zone, buf, length); |
| 14170 | } |
| 14171 | |
| 14172 | void |
| 14173 | dns_zone_logv(dns_zone_t *zone, isc_logcategory_t *category, int level, |
| 14174 | const char *prefix, const char *fmt, va_list ap) |
| 14175 | { |
| 14176 | char message[4096]; |
| 14177 | const char *zstr; |
| 14178 | |
| 14179 | if (!isc_log_wouldlog(dns_lctx, level)) { |
| 14180 | return; |
| 14181 | } |
| 14182 | |
| 14183 | vsnprintf(message, sizeof(message), fmt, ap); |
| 14184 | |
| 14185 | switch (zone->type) { |
| 14186 | case dns_zone_key: |
| 14187 | zstr = "managed-keys-zone" ; |
| 14188 | break; |
| 14189 | case dns_zone_redirect: |
| 14190 | zstr = "redirect-zone" ; |
| 14191 | break; |
| 14192 | default: |
| 14193 | zstr = "zone " ; |
| 14194 | } |
| 14195 | |
| 14196 | isc_log_write(dns_lctx, category, DNS_LOGMODULE_ZONE, level, |
| 14197 | "%s%s%s%s: %s" , |
| 14198 | (prefix != NULL ? prefix : "" ), |
| 14199 | (prefix != NULL ? ": " : "" ), |
| 14200 | zstr, zone->strnamerd, message); |
| 14201 | } |
| 14202 | |
| 14203 | static void |
| 14204 | notify_log(dns_zone_t *zone, int level, const char *fmt, ...) { |
| 14205 | va_list ap; |
| 14206 | |
| 14207 | va_start(ap, fmt); |
| 14208 | dns_zone_logv(zone, DNS_LOGCATEGORY_NOTIFY, level, NULL, fmt, ap); |
| 14209 | va_end(ap); |
| 14210 | } |
| 14211 | |
| 14212 | void |
| 14213 | dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category, |
| 14214 | int level, const char *fmt, ...) |
| 14215 | { |
| 14216 | va_list ap; |
| 14217 | |
| 14218 | va_start(ap, fmt); |
| 14219 | dns_zone_logv(zone, category, level, NULL, fmt, ap); |
| 14220 | va_end(ap); |
| 14221 | } |
| 14222 | |
| 14223 | void |
| 14224 | dns_zone_log(dns_zone_t *zone, int level, const char *fmt, ...) { |
| 14225 | va_list ap; |
| 14226 | |
| 14227 | va_start(ap, fmt); |
| 14228 | dns_zone_logv(zone, DNS_LOGCATEGORY_GENERAL, level, NULL, fmt, ap); |
| 14229 | va_end(ap); |
| 14230 | } |
| 14231 | |
| 14232 | static void |
| 14233 | zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel, |
| 14234 | const char *fmt, ...) |
| 14235 | { |
| 14236 | int level = ISC_LOG_DEBUG(debuglevel); |
| 14237 | va_list ap; |
| 14238 | |
| 14239 | va_start(ap, fmt); |
| 14240 | dns_zone_logv(zone, DNS_LOGCATEGORY_GENERAL, level, me, fmt, ap); |
| 14241 | va_end(ap); |
| 14242 | } |
| 14243 | |
| 14244 | static void |
| 14245 | dnssec_log(dns_zone_t *zone, int level, const char *fmt, ...) { |
| 14246 | va_list ap; |
| 14247 | |
| 14248 | va_start(ap, fmt); |
| 14249 | dns_zone_logv(zone, DNS_LOGCATEGORY_DNSSEC, level, NULL, fmt, ap); |
| 14250 | va_end(ap); |
| 14251 | } |
| 14252 | |
| 14253 | static int |
| 14254 | message_count(dns_message_t *msg, dns_section_t section, dns_rdatatype_t type) |
| 14255 | { |
| 14256 | isc_result_t result; |
| 14257 | dns_name_t *name; |
| 14258 | dns_rdataset_t *curr; |
| 14259 | int count = 0; |
| 14260 | |
| 14261 | result = dns_message_firstname(msg, section); |
| 14262 | while (result == ISC_R_SUCCESS) { |
| 14263 | name = NULL; |
| 14264 | dns_message_currentname(msg, section, &name); |
| 14265 | |
| 14266 | for (curr = ISC_LIST_TAIL(name->list); curr != NULL; |
| 14267 | curr = ISC_LIST_PREV(curr, link)) { |
| 14268 | if (curr->type == type) |
| 14269 | count++; |
| 14270 | } |
| 14271 | result = dns_message_nextname(msg, section); |
| 14272 | } |
| 14273 | |
| 14274 | return (count); |
| 14275 | } |
| 14276 | |
| 14277 | void |
| 14278 | dns_zone_setmaxxfrin(dns_zone_t *zone, uint32_t maxxfrin) { |
| 14279 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14280 | |
| 14281 | zone->maxxfrin = maxxfrin; |
| 14282 | } |
| 14283 | |
| 14284 | uint32_t |
| 14285 | dns_zone_getmaxxfrin(dns_zone_t *zone) { |
| 14286 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14287 | |
| 14288 | return (zone->maxxfrin); |
| 14289 | } |
| 14290 | |
| 14291 | void |
| 14292 | dns_zone_setmaxxfrout(dns_zone_t *zone, uint32_t maxxfrout) { |
| 14293 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14294 | zone->maxxfrout = maxxfrout; |
| 14295 | } |
| 14296 | |
| 14297 | uint32_t |
| 14298 | dns_zone_getmaxxfrout(dns_zone_t *zone) { |
| 14299 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14300 | |
| 14301 | return (zone->maxxfrout); |
| 14302 | } |
| 14303 | |
| 14304 | dns_zonetype_t |
| 14305 | dns_zone_gettype(dns_zone_t *zone) { |
| 14306 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14307 | |
| 14308 | return (zone->type); |
| 14309 | } |
| 14310 | |
| 14311 | dns_zonetype_t |
| 14312 | dns_zone_getredirecttype(dns_zone_t *zone) { |
| 14313 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14314 | REQUIRE(zone->type == dns_zone_redirect); |
| 14315 | |
| 14316 | return (zone->masters == NULL ? dns_zone_master : dns_zone_slave); |
| 14317 | } |
| 14318 | |
| 14319 | dns_name_t * |
| 14320 | dns_zone_getorigin(dns_zone_t *zone) { |
| 14321 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14322 | |
| 14323 | return (&zone->origin); |
| 14324 | } |
| 14325 | |
| 14326 | void |
| 14327 | dns_zone_settask(dns_zone_t *zone, isc_task_t *task) { |
| 14328 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14329 | |
| 14330 | LOCK_ZONE(zone); |
| 14331 | if (zone->task != NULL) |
| 14332 | isc_task_detach(&zone->task); |
| 14333 | isc_task_attach(task, &zone->task); |
| 14334 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 14335 | if (zone->db != NULL) |
| 14336 | dns_db_settask(zone->db, zone->task); |
| 14337 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 14338 | UNLOCK_ZONE(zone); |
| 14339 | } |
| 14340 | |
| 14341 | void |
| 14342 | dns_zone_gettask(dns_zone_t *zone, isc_task_t **target) { |
| 14343 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14344 | isc_task_attach(zone->task, target); |
| 14345 | } |
| 14346 | |
| 14347 | void |
| 14348 | dns_zone_setidlein(dns_zone_t *zone, uint32_t idlein) { |
| 14349 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14350 | |
| 14351 | if (idlein == 0) |
| 14352 | idlein = DNS_DEFAULT_IDLEIN; |
| 14353 | zone->idlein = idlein; |
| 14354 | } |
| 14355 | |
| 14356 | uint32_t |
| 14357 | dns_zone_getidlein(dns_zone_t *zone) { |
| 14358 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14359 | |
| 14360 | return (zone->idlein); |
| 14361 | } |
| 14362 | |
| 14363 | void |
| 14364 | dns_zone_setidleout(dns_zone_t *zone, uint32_t idleout) { |
| 14365 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14366 | |
| 14367 | zone->idleout = idleout; |
| 14368 | } |
| 14369 | |
| 14370 | uint32_t |
| 14371 | dns_zone_getidleout(dns_zone_t *zone) { |
| 14372 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14373 | |
| 14374 | return (zone->idleout); |
| 14375 | } |
| 14376 | |
| 14377 | static void |
| 14378 | notify_done(isc_task_t *task, isc_event_t *event) { |
| 14379 | dns_requestevent_t *revent = (dns_requestevent_t *)event; |
| 14380 | dns_notify_t *notify; |
| 14381 | isc_result_t result; |
| 14382 | dns_message_t *message = NULL; |
| 14383 | isc_buffer_t buf; |
| 14384 | char rcode[128]; |
| 14385 | char addrbuf[ISC_SOCKADDR_FORMATSIZE]; |
| 14386 | |
| 14387 | UNUSED(task); |
| 14388 | |
| 14389 | notify = event->ev_arg; |
| 14390 | REQUIRE(DNS_NOTIFY_VALID(notify)); |
| 14391 | INSIST(task == notify->zone->task); |
| 14392 | |
| 14393 | isc_buffer_init(&buf, rcode, sizeof(rcode)); |
| 14394 | isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); |
| 14395 | |
| 14396 | result = revent->result; |
| 14397 | if (result == ISC_R_SUCCESS) |
| 14398 | result = dns_message_create(notify->zone->mctx, |
| 14399 | DNS_MESSAGE_INTENTPARSE, &message); |
| 14400 | if (result == ISC_R_SUCCESS) |
| 14401 | result = dns_request_getresponse(revent->request, message, |
| 14402 | DNS_MESSAGEPARSE_PRESERVEORDER); |
| 14403 | if (result == ISC_R_SUCCESS) |
| 14404 | result = dns_rcode_totext(message->rcode, &buf); |
| 14405 | if (result == ISC_R_SUCCESS) |
| 14406 | notify_log(notify->zone, ISC_LOG_DEBUG(3), |
| 14407 | "notify response from %s: %.*s" , |
| 14408 | addrbuf, (int)buf.used, rcode); |
| 14409 | else |
| 14410 | notify_log(notify->zone, ISC_LOG_DEBUG(2), |
| 14411 | "notify to %s failed: %s" , addrbuf, |
| 14412 | dns_result_totext(result)); |
| 14413 | |
| 14414 | /* |
| 14415 | * Old bind's return formerr if they see a soa record. Retry w/o |
| 14416 | * the soa if we see a formerr and had sent a SOA. |
| 14417 | */ |
| 14418 | isc_event_free(&event); |
| 14419 | if (message != NULL && message->rcode == dns_rcode_formerr && |
| 14420 | (notify->flags & DNS_NOTIFY_NOSOA) == 0) { |
| 14421 | bool startup; |
| 14422 | |
| 14423 | notify->flags |= DNS_NOTIFY_NOSOA; |
| 14424 | dns_request_destroy(¬ify->request); |
| 14425 | startup = (notify->flags & DNS_NOTIFY_STARTUP); |
| 14426 | result = notify_send_queue(notify, startup); |
| 14427 | if (result != ISC_R_SUCCESS) |
| 14428 | notify_destroy(notify, false); |
| 14429 | } else { |
| 14430 | if (result == ISC_R_TIMEDOUT) |
| 14431 | notify_log(notify->zone, ISC_LOG_DEBUG(1), |
| 14432 | "notify to %s: retries exceeded" , addrbuf); |
| 14433 | notify_destroy(notify, false); |
| 14434 | } |
| 14435 | if (message != NULL) |
| 14436 | dns_message_destroy(&message); |
| 14437 | } |
| 14438 | |
| 14439 | struct secure_event { |
| 14440 | isc_event_t e; |
| 14441 | dns_db_t *db; |
| 14442 | uint32_t serial; |
| 14443 | }; |
| 14444 | |
| 14445 | static void |
| 14446 | update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) { |
| 14447 | UNUSED(arg); |
| 14448 | dns_zone_log(zone, level, "%s" , message); |
| 14449 | } |
| 14450 | |
| 14451 | static isc_result_t |
| 14452 | sync_secure_journal(dns_zone_t *zone, dns_zone_t *raw, dns_journal_t *journal, |
| 14453 | uint32_t start, uint32_t end, |
| 14454 | dns_difftuple_t **soatuplep, dns_diff_t *diff) |
| 14455 | { |
| 14456 | isc_result_t result; |
| 14457 | dns_difftuple_t *tuple = NULL; |
| 14458 | dns_diffop_t op = DNS_DIFFOP_ADD; |
| 14459 | int n_soa = 0; |
| 14460 | |
| 14461 | REQUIRE(soatuplep != NULL); |
| 14462 | |
| 14463 | if (start == end) |
| 14464 | return (DNS_R_UNCHANGED); |
| 14465 | |
| 14466 | CHECK(dns_journal_iter_init(journal, start, end)); |
| 14467 | for (result = dns_journal_first_rr(journal); |
| 14468 | result == ISC_R_SUCCESS; |
| 14469 | result = dns_journal_next_rr(journal)) |
| 14470 | { |
| 14471 | dns_name_t *name = NULL; |
| 14472 | uint32_t ttl; |
| 14473 | dns_rdata_t *rdata = NULL; |
| 14474 | dns_journal_current_rr(journal, &name, &ttl, &rdata); |
| 14475 | |
| 14476 | if (rdata->type == dns_rdatatype_soa) { |
| 14477 | n_soa++; |
| 14478 | if (n_soa == 2) { |
| 14479 | /* |
| 14480 | * Save the latest raw SOA record. |
| 14481 | */ |
| 14482 | if (*soatuplep != NULL) |
| 14483 | dns_difftuple_free(soatuplep); |
| 14484 | CHECK(dns_difftuple_create(diff->mctx, |
| 14485 | DNS_DIFFOP_ADD, |
| 14486 | name, ttl, rdata, |
| 14487 | soatuplep)); |
| 14488 | } |
| 14489 | if (n_soa == 3) |
| 14490 | n_soa = 1; |
| 14491 | continue; |
| 14492 | } |
| 14493 | |
| 14494 | /* Sanity. */ |
| 14495 | if (n_soa == 0) { |
| 14496 | dns_zone_log(raw, ISC_LOG_ERROR, |
| 14497 | "corrupt journal file: '%s'\n" , |
| 14498 | raw->journal); |
| 14499 | return (ISC_R_FAILURE); |
| 14500 | } |
| 14501 | |
| 14502 | if (zone->privatetype != 0 && |
| 14503 | rdata->type == zone->privatetype) |
| 14504 | continue; |
| 14505 | |
| 14506 | if (rdata->type == dns_rdatatype_nsec || |
| 14507 | rdata->type == dns_rdatatype_rrsig || |
| 14508 | rdata->type == dns_rdatatype_nsec3 || |
| 14509 | rdata->type == dns_rdatatype_dnskey || |
| 14510 | rdata->type == dns_rdatatype_nsec3param) |
| 14511 | continue; |
| 14512 | |
| 14513 | op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD; |
| 14514 | |
| 14515 | CHECK(dns_difftuple_create(diff->mctx, op, name, ttl, rdata, |
| 14516 | &tuple)); |
| 14517 | dns_diff_appendminimal(diff, &tuple); |
| 14518 | } |
| 14519 | if (result == ISC_R_NOMORE) |
| 14520 | result = ISC_R_SUCCESS; |
| 14521 | |
| 14522 | failure: |
| 14523 | return(result); |
| 14524 | } |
| 14525 | |
| 14526 | static isc_result_t |
| 14527 | sync_secure_db(dns_zone_t *seczone, dns_zone_t *raw, dns_db_t *secdb, |
| 14528 | dns_dbversion_t *secver, dns_difftuple_t **soatuple, |
| 14529 | dns_diff_t *diff) |
| 14530 | { |
| 14531 | isc_result_t result; |
| 14532 | dns_db_t *rawdb = NULL; |
| 14533 | dns_dbversion_t *rawver = NULL; |
| 14534 | dns_difftuple_t *tuple = NULL, *next; |
| 14535 | dns_difftuple_t *oldtuple = NULL, *newtuple = NULL; |
| 14536 | dns_rdata_soa_t oldsoa, newsoa; |
| 14537 | |
| 14538 | REQUIRE(DNS_ZONE_VALID(seczone)); |
| 14539 | REQUIRE(soatuple != NULL && *soatuple == NULL); |
| 14540 | |
| 14541 | if (!seczone->sourceserialset) |
| 14542 | return (DNS_R_UNCHANGED); |
| 14543 | |
| 14544 | dns_db_attach(raw->db, &rawdb); |
| 14545 | dns_db_currentversion(rawdb, &rawver); |
| 14546 | result = dns_db_diffx(diff, rawdb, rawver, secdb, secver, NULL); |
| 14547 | dns_db_closeversion(rawdb, &rawver, false); |
| 14548 | dns_db_detach(&rawdb); |
| 14549 | |
| 14550 | if (result != ISC_R_SUCCESS) |
| 14551 | return (result); |
| 14552 | |
| 14553 | for (tuple = ISC_LIST_HEAD(diff->tuples); |
| 14554 | tuple != NULL; |
| 14555 | tuple = next) |
| 14556 | { |
| 14557 | next = ISC_LIST_NEXT(tuple, link); |
| 14558 | if (tuple->rdata.type == dns_rdatatype_nsec || |
| 14559 | tuple->rdata.type == dns_rdatatype_rrsig || |
| 14560 | tuple->rdata.type == dns_rdatatype_dnskey || |
| 14561 | tuple->rdata.type == dns_rdatatype_nsec3 || |
| 14562 | tuple->rdata.type == dns_rdatatype_nsec3param) |
| 14563 | { |
| 14564 | ISC_LIST_UNLINK(diff->tuples, tuple, link); |
| 14565 | dns_difftuple_free(&tuple); |
| 14566 | continue; |
| 14567 | } |
| 14568 | if (tuple->rdata.type == dns_rdatatype_soa) { |
| 14569 | if (tuple->op == DNS_DIFFOP_DEL) { |
| 14570 | INSIST(oldtuple == NULL); |
| 14571 | oldtuple = tuple; |
| 14572 | } |
| 14573 | if (tuple->op == DNS_DIFFOP_ADD) { |
| 14574 | INSIST(newtuple == NULL); |
| 14575 | newtuple = tuple; |
| 14576 | } |
| 14577 | } |
| 14578 | } |
| 14579 | |
| 14580 | if (oldtuple != NULL && newtuple != NULL) { |
| 14581 | |
| 14582 | result = dns_rdata_tostruct(&oldtuple->rdata, &oldsoa, NULL); |
| 14583 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 14584 | |
| 14585 | result = dns_rdata_tostruct(&newtuple->rdata, &newsoa, NULL); |
| 14586 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 14587 | |
| 14588 | /* |
| 14589 | * If the SOA records are the same except for the serial |
| 14590 | * remove them from the diff. |
| 14591 | */ |
| 14592 | if (oldsoa.refresh == newsoa.refresh && |
| 14593 | oldsoa.retry == newsoa.retry && |
| 14594 | oldsoa.minimum == newsoa.minimum && |
| 14595 | oldsoa.expire == newsoa.expire && |
| 14596 | dns_name_equal(&oldsoa.origin, &newsoa.origin) && |
| 14597 | dns_name_equal(&oldsoa.contact, &newsoa.contact)) { |
| 14598 | ISC_LIST_UNLINK(diff->tuples, oldtuple, link); |
| 14599 | dns_difftuple_free(&oldtuple); |
| 14600 | ISC_LIST_UNLINK(diff->tuples, newtuple, link); |
| 14601 | dns_difftuple_free(&newtuple); |
| 14602 | } |
| 14603 | } |
| 14604 | |
| 14605 | if (ISC_LIST_EMPTY(diff->tuples)) |
| 14606 | return (DNS_R_UNCHANGED); |
| 14607 | |
| 14608 | /* |
| 14609 | * If there are still SOA records in the diff they can now be removed |
| 14610 | * saving the new SOA record. |
| 14611 | */ |
| 14612 | if (oldtuple != NULL) { |
| 14613 | ISC_LIST_UNLINK(diff->tuples, oldtuple, link); |
| 14614 | dns_difftuple_free(&oldtuple); |
| 14615 | } |
| 14616 | |
| 14617 | if (newtuple != NULL) { |
| 14618 | ISC_LIST_UNLINK(diff->tuples, newtuple, link); |
| 14619 | *soatuple = newtuple; |
| 14620 | } |
| 14621 | |
| 14622 | return (ISC_R_SUCCESS); |
| 14623 | } |
| 14624 | |
| 14625 | static void |
| 14626 | receive_secure_serial(isc_task_t *task, isc_event_t *event) { |
| 14627 | static char me[] = "receive_secure_serial" ; |
| 14628 | isc_result_t result = ISC_R_SUCCESS; |
| 14629 | dns_journal_t *rjournal = NULL; |
| 14630 | dns_journal_t *sjournal = NULL; |
| 14631 | uint32_t start, end; |
| 14632 | dns_zone_t *zone; |
| 14633 | dns_difftuple_t *tuple = NULL, *soatuple = NULL; |
| 14634 | dns_update_log_t log = { update_log_cb, NULL }; |
| 14635 | uint32_t newserial = 0, desired = 0; |
| 14636 | isc_time_t timenow; |
| 14637 | |
| 14638 | UNUSED(task); |
| 14639 | |
| 14640 | zone = event->ev_arg; |
| 14641 | end = ((struct secure_event *)event)->serial; |
| 14642 | |
| 14643 | ENTER; |
| 14644 | |
| 14645 | LOCK_ZONE(zone); |
| 14646 | |
| 14647 | /* |
| 14648 | * If we are already processing a receive secure serial event |
| 14649 | * for the zone, just queue the new one and exit. |
| 14650 | */ |
| 14651 | if (zone->rss_event != NULL && zone->rss_event != event) { |
| 14652 | ISC_LIST_APPEND(zone->rss_events, event, ev_link); |
| 14653 | UNLOCK_ZONE(zone); |
| 14654 | return; |
| 14655 | } |
| 14656 | |
| 14657 | nextevent: |
| 14658 | if (zone->rss_event != NULL) { |
| 14659 | INSIST(zone->rss_event == event); |
| 14660 | UNLOCK_ZONE(zone); |
| 14661 | } else { |
| 14662 | zone->rss_event = event; |
| 14663 | dns_diff_init(zone->mctx, &zone->rss_diff); |
| 14664 | |
| 14665 | /* |
| 14666 | * zone->db may be NULL, if the load from disk failed. |
| 14667 | */ |
| 14668 | result = ISC_R_SUCCESS; |
| 14669 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 14670 | if (zone->db != NULL) |
| 14671 | dns_db_attach(zone->db, &zone->rss_db); |
| 14672 | else |
| 14673 | result = ISC_R_FAILURE; |
| 14674 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 14675 | |
| 14676 | if (result == ISC_R_SUCCESS && zone->raw != NULL) |
| 14677 | dns_zone_attach(zone->raw, &zone->rss_raw); |
| 14678 | else |
| 14679 | result = ISC_R_FAILURE; |
| 14680 | |
| 14681 | UNLOCK_ZONE(zone); |
| 14682 | |
| 14683 | CHECK(result); |
| 14684 | |
| 14685 | /* |
| 14686 | * We first attempt to sync the raw zone to the secure zone |
| 14687 | * by using the raw zone's journal, applying all the deltas |
| 14688 | * from the latest source-serial of the secure zone up to |
| 14689 | * the current serial number of the raw zone. |
| 14690 | * |
| 14691 | * If that fails, then we'll fall back to a direct comparison |
| 14692 | * between raw and secure zones. |
| 14693 | */ |
| 14694 | CHECK(dns_journal_open(zone->rss_raw->mctx, |
| 14695 | zone->rss_raw->journal, |
| 14696 | DNS_JOURNAL_WRITE, &rjournal)); |
| 14697 | |
| 14698 | result = dns_journal_open(zone->mctx, zone->journal, |
| 14699 | DNS_JOURNAL_READ, &sjournal); |
| 14700 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) |
| 14701 | goto failure; |
| 14702 | |
| 14703 | if (!dns_journal_get_sourceserial(rjournal, &start)) { |
| 14704 | start = dns_journal_first_serial(rjournal); |
| 14705 | dns_journal_set_sourceserial(rjournal, start); |
| 14706 | } |
| 14707 | if (sjournal != NULL) { |
| 14708 | uint32_t serial; |
| 14709 | /* |
| 14710 | * We read the secure journal first, if that |
| 14711 | * exists use its value provided it is greater |
| 14712 | * that from the raw journal. |
| 14713 | */ |
| 14714 | if (dns_journal_get_sourceserial(sjournal, &serial)) { |
| 14715 | if (isc_serial_gt(serial, start)) |
| 14716 | start = serial; |
| 14717 | } |
| 14718 | dns_journal_destroy(&sjournal); |
| 14719 | } |
| 14720 | |
| 14721 | dns_db_currentversion(zone->rss_db, &zone->rss_oldver); |
| 14722 | CHECK(dns_db_newversion(zone->rss_db, &zone->rss_newver)); |
| 14723 | |
| 14724 | /* |
| 14725 | * Try to apply diffs from the raw zone's journal to the secure |
| 14726 | * zone. If that fails, we recover by syncing up the databases |
| 14727 | * directly. |
| 14728 | */ |
| 14729 | result = sync_secure_journal(zone, zone->rss_raw, rjournal, |
| 14730 | start, end, &soatuple, |
| 14731 | &zone->rss_diff); |
| 14732 | if (result == DNS_R_UNCHANGED) |
| 14733 | goto failure; |
| 14734 | else if (result != ISC_R_SUCCESS) |
| 14735 | CHECK(sync_secure_db(zone, zone->rss_raw, zone->rss_db, |
| 14736 | zone->rss_oldver, &soatuple, |
| 14737 | &zone->rss_diff)); |
| 14738 | |
| 14739 | CHECK(dns_diff_apply(&zone->rss_diff, zone->rss_db, |
| 14740 | zone->rss_newver)); |
| 14741 | |
| 14742 | if (soatuple != NULL) { |
| 14743 | uint32_t oldserial; |
| 14744 | |
| 14745 | CHECK(dns_db_createsoatuple(zone->rss_db, |
| 14746 | zone->rss_oldver, |
| 14747 | zone->rss_diff.mctx, |
| 14748 | DNS_DIFFOP_DEL, &tuple)); |
| 14749 | oldserial = dns_soa_getserial(&tuple->rdata); |
| 14750 | newserial = desired = |
| 14751 | dns_soa_getserial(&soatuple->rdata); |
| 14752 | if (!isc_serial_gt(newserial, oldserial)) { |
| 14753 | newserial = oldserial + 1; |
| 14754 | if (newserial == 0) |
| 14755 | newserial++; |
| 14756 | dns_soa_setserial(newserial, &soatuple->rdata); |
| 14757 | } |
| 14758 | CHECK(do_one_tuple(&tuple, zone->rss_db, |
| 14759 | zone->rss_newver, &zone->rss_diff)); |
| 14760 | CHECK(do_one_tuple(&soatuple, zone->rss_db, |
| 14761 | zone->rss_newver, &zone->rss_diff)); |
| 14762 | } else |
| 14763 | CHECK(update_soa_serial(zone->rss_db, zone->rss_newver, |
| 14764 | &zone->rss_diff, zone->mctx, |
| 14765 | zone->updatemethod)); |
| 14766 | |
| 14767 | } |
| 14768 | result = dns_update_signaturesinc(&log, zone, zone->rss_db, |
| 14769 | zone->rss_oldver, zone->rss_newver, |
| 14770 | &zone->rss_diff, |
| 14771 | zone->sigvalidityinterval, |
| 14772 | &zone->rss_state); |
| 14773 | if (result == DNS_R_CONTINUE) { |
| 14774 | if (rjournal != NULL) |
| 14775 | dns_journal_destroy(&rjournal); |
| 14776 | isc_task_send(task, &event); |
| 14777 | return; |
| 14778 | } |
| 14779 | /* |
| 14780 | * If something went wrong while trying to update the secure zone and |
| 14781 | * the latter was already signed before, do not apply raw zone deltas |
| 14782 | * to it as that would break existing DNSSEC signatures. However, if |
| 14783 | * the secure zone was not yet signed (e.g. because no signing keys |
| 14784 | * were created for it), commence applying raw zone deltas to it so |
| 14785 | * that contents of the raw zone and the secure zone are kept in sync. |
| 14786 | */ |
| 14787 | if (result != ISC_R_SUCCESS && dns_db_issecure(zone->rss_db)) { |
| 14788 | goto failure; |
| 14789 | } |
| 14790 | |
| 14791 | if (rjournal == NULL) |
| 14792 | CHECK(dns_journal_open(zone->rss_raw->mctx, |
| 14793 | zone->rss_raw->journal, |
| 14794 | DNS_JOURNAL_WRITE, &rjournal)); |
| 14795 | CHECK(zone_journal(zone, &zone->rss_diff, &end, |
| 14796 | "receive_secure_serial" )); |
| 14797 | |
| 14798 | dns_journal_set_sourceserial(rjournal, end); |
| 14799 | dns_journal_commit(rjournal); |
| 14800 | |
| 14801 | LOCK_ZONE(zone); |
| 14802 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 14803 | |
| 14804 | zone->sourceserial = end; |
| 14805 | zone->sourceserialset = true; |
| 14806 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 14807 | |
| 14808 | TIME_NOW(&timenow); |
| 14809 | zone_settimer(zone, &timenow); |
| 14810 | UNLOCK_ZONE(zone); |
| 14811 | |
| 14812 | dns_db_closeversion(zone->rss_db, &zone->rss_oldver, false); |
| 14813 | dns_db_closeversion(zone->rss_db, &zone->rss_newver, true); |
| 14814 | |
| 14815 | if (newserial != 0) { |
| 14816 | dns_zone_log(zone, ISC_LOG_INFO, "serial %u (unsigned %u)" , |
| 14817 | newserial, desired); |
| 14818 | } |
| 14819 | |
| 14820 | failure: |
| 14821 | isc_event_free(&zone->rss_event); |
| 14822 | event = ISC_LIST_HEAD(zone->rss_events); |
| 14823 | |
| 14824 | if (zone->rss_raw != NULL) |
| 14825 | dns_zone_detach(&zone->rss_raw); |
| 14826 | if (result != ISC_R_SUCCESS) |
| 14827 | dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_serial: %s" , |
| 14828 | dns_result_totext(result)); |
| 14829 | if (tuple != NULL) |
| 14830 | dns_difftuple_free(&tuple); |
| 14831 | if (soatuple != NULL) |
| 14832 | dns_difftuple_free(&soatuple); |
| 14833 | if (zone->rss_db != NULL) { |
| 14834 | if (zone->rss_oldver != NULL) |
| 14835 | dns_db_closeversion(zone->rss_db, &zone->rss_oldver, |
| 14836 | false); |
| 14837 | if (zone->rss_newver != NULL) |
| 14838 | dns_db_closeversion(zone->rss_db, &zone->rss_newver, |
| 14839 | false); |
| 14840 | dns_db_detach(&zone->rss_db); |
| 14841 | } |
| 14842 | INSIST(zone->rss_oldver == NULL); |
| 14843 | INSIST(zone->rss_newver == NULL); |
| 14844 | if (rjournal != NULL) |
| 14845 | dns_journal_destroy(&rjournal); |
| 14846 | dns_diff_clear(&zone->rss_diff); |
| 14847 | |
| 14848 | if (event != NULL) { |
| 14849 | LOCK_ZONE(zone); |
| 14850 | INSIST(zone->irefs > 1); |
| 14851 | zone->irefs--; |
| 14852 | ISC_LIST_UNLINK(zone->rss_events, event, ev_link); |
| 14853 | goto nextevent; |
| 14854 | } |
| 14855 | dns_zone_idetach(&zone); |
| 14856 | } |
| 14857 | |
| 14858 | static isc_result_t |
| 14859 | zone_send_secureserial(dns_zone_t *zone, uint32_t serial) { |
| 14860 | isc_event_t *e; |
| 14861 | dns_zone_t *dummy = NULL; |
| 14862 | |
| 14863 | e = isc_event_allocate(zone->secure->mctx, zone, |
| 14864 | DNS_EVENT_ZONESECURESERIAL, |
| 14865 | receive_secure_serial, zone->secure, |
| 14866 | sizeof(struct secure_event)); |
| 14867 | if (e == NULL) |
| 14868 | return (ISC_R_NOMEMORY); |
| 14869 | ((struct secure_event *)e)->serial = serial; |
| 14870 | INSIST(LOCKED_ZONE(zone->secure)); |
| 14871 | zone_iattach(zone->secure, &dummy); |
| 14872 | isc_task_send(zone->secure->task, &e); |
| 14873 | |
| 14874 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE); |
| 14875 | return (ISC_R_SUCCESS); |
| 14876 | } |
| 14877 | |
| 14878 | static isc_result_t |
| 14879 | checkandaddsoa(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, |
| 14880 | dns_rdataset_t *rdataset, uint32_t oldserial) |
| 14881 | { |
| 14882 | dns_rdata_soa_t soa; |
| 14883 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 14884 | dns_rdatalist_t temprdatalist; |
| 14885 | dns_rdataset_t temprdataset; |
| 14886 | isc_buffer_t b; |
| 14887 | isc_result_t result; |
| 14888 | unsigned char buf[DNS_SOA_BUFFERSIZE]; |
| 14889 | dns_fixedname_t fixed; |
| 14890 | dns_name_t *name; |
| 14891 | |
| 14892 | result = dns_rdataset_first(rdataset); |
| 14893 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 14894 | dns_rdataset_current(rdataset, &rdata); |
| 14895 | result = dns_rdata_tostruct(&rdata, &soa, NULL); |
| 14896 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 14897 | |
| 14898 | if (isc_serial_gt(soa.serial, oldserial)) |
| 14899 | return (dns_db_addrdataset(db, node, version, 0, rdataset, 0, |
| 14900 | NULL)); |
| 14901 | /* |
| 14902 | * Always bump the serial. |
| 14903 | */ |
| 14904 | oldserial++; |
| 14905 | if (oldserial == 0) |
| 14906 | oldserial++; |
| 14907 | soa.serial = oldserial; |
| 14908 | |
| 14909 | /* |
| 14910 | * Construct a replacement rdataset. |
| 14911 | */ |
| 14912 | dns_rdata_reset(&rdata); |
| 14913 | isc_buffer_init(&b, buf, sizeof(buf)); |
| 14914 | result = dns_rdata_fromstruct(&rdata, rdataset->rdclass, |
| 14915 | dns_rdatatype_soa, &soa, &b); |
| 14916 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 14917 | dns_rdatalist_init(&temprdatalist); |
| 14918 | temprdatalist.rdclass = rdata.rdclass; |
| 14919 | temprdatalist.type = rdata.type; |
| 14920 | temprdatalist.ttl = rdataset->ttl; |
| 14921 | ISC_LIST_APPEND(temprdatalist.rdata, &rdata, link); |
| 14922 | |
| 14923 | dns_rdataset_init(&temprdataset); |
| 14924 | result = dns_rdatalist_tordataset(&temprdatalist, &temprdataset); |
| 14925 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 14926 | |
| 14927 | name = dns_fixedname_initname(&fixed); |
| 14928 | result = dns_db_nodefullname(db, node, name); |
| 14929 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 14930 | dns_rdataset_getownercase(rdataset, name); |
| 14931 | dns_rdataset_setownercase(&temprdataset, name); |
| 14932 | return (dns_db_addrdataset(db, node, version, 0, &temprdataset, |
| 14933 | 0, NULL)); |
| 14934 | } |
| 14935 | |
| 14936 | /* |
| 14937 | * This function should populate an nsec3paramlist_t with the |
| 14938 | * nsecparam_t data from a zone. |
| 14939 | */ |
| 14940 | static isc_result_t |
| 14941 | save_nsec3param(dns_zone_t *zone, nsec3paramlist_t *nsec3list) { |
| 14942 | isc_result_t result; |
| 14943 | dns_dbnode_t *node = NULL; |
| 14944 | dns_rdataset_t rdataset, prdataset; |
| 14945 | dns_dbversion_t *version = NULL; |
| 14946 | nsec3param_t *nsec3param = NULL; |
| 14947 | nsec3param_t *nsec3p = NULL; |
| 14948 | nsec3param_t *next; |
| 14949 | dns_db_t *db = NULL; |
| 14950 | unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; |
| 14951 | |
| 14952 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 14953 | REQUIRE(nsec3list != NULL); |
| 14954 | REQUIRE(ISC_LIST_EMPTY(*nsec3list)); |
| 14955 | |
| 14956 | dns_rdataset_init(&rdataset); |
| 14957 | dns_rdataset_init(&prdataset); |
| 14958 | |
| 14959 | dns_db_attach(zone->db, &db); |
| 14960 | CHECK(dns_db_getoriginnode(db, &node)); |
| 14961 | |
| 14962 | dns_db_currentversion(db, &version); |
| 14963 | result = dns_db_findrdataset(db, node, version, |
| 14964 | dns_rdatatype_nsec3param, |
| 14965 | dns_rdatatype_none, 0, &rdataset, NULL); |
| 14966 | |
| 14967 | if (result != ISC_R_SUCCESS) |
| 14968 | goto getprivate; |
| 14969 | |
| 14970 | /* |
| 14971 | * walk nsec3param rdataset making a list of parameters (note that |
| 14972 | * multiple simultaneous nsec3 chains are annoyingly legal -- this |
| 14973 | * is why we use an nsec3list, even tho we will usually only have |
| 14974 | * one) |
| 14975 | */ |
| 14976 | for (result = dns_rdataset_first(&rdataset); |
| 14977 | result == ISC_R_SUCCESS; |
| 14978 | result = dns_rdataset_next(&rdataset)) |
| 14979 | { |
| 14980 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 14981 | dns_rdata_t private = DNS_RDATA_INIT; |
| 14982 | |
| 14983 | dns_rdataset_current(&rdataset, &rdata); |
| 14984 | isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, |
| 14985 | DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), |
| 14986 | "looping through nsec3param data" ); |
| 14987 | nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t)); |
| 14988 | if (nsec3param == NULL) |
| 14989 | CHECK(ISC_R_NOMEMORY); |
| 14990 | ISC_LINK_INIT(nsec3param, link); |
| 14991 | |
| 14992 | /* |
| 14993 | * now transfer the data from the rdata to |
| 14994 | * the nsec3param |
| 14995 | */ |
| 14996 | dns_nsec3param_toprivate(&rdata, &private, |
| 14997 | zone->privatetype, nsec3param->data, |
| 14998 | sizeof(nsec3param->data)); |
| 14999 | nsec3param->length = private.length; |
| 15000 | ISC_LIST_APPEND(*nsec3list, nsec3param, link); |
| 15001 | } |
| 15002 | |
| 15003 | getprivate: |
| 15004 | result = dns_db_findrdataset(db, node, version, zone->privatetype, |
| 15005 | dns_rdatatype_none, 0, &prdataset, NULL); |
| 15006 | if (result != ISC_R_SUCCESS) |
| 15007 | goto done; |
| 15008 | |
| 15009 | /* |
| 15010 | * walk private type records, converting them to nsec3 parameters |
| 15011 | * using dns_nsec3param_fromprivate(), do the right thing based on |
| 15012 | * CREATE and REMOVE flags |
| 15013 | */ |
| 15014 | for (result = dns_rdataset_first(&prdataset); |
| 15015 | result == ISC_R_SUCCESS; |
| 15016 | result = dns_rdataset_next(&prdataset)) |
| 15017 | { |
| 15018 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 15019 | dns_rdata_t private = DNS_RDATA_INIT; |
| 15020 | |
| 15021 | dns_rdataset_current(&prdataset, &private); |
| 15022 | isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, |
| 15023 | DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), |
| 15024 | "looping through nsec3param private data" ); |
| 15025 | |
| 15026 | /* |
| 15027 | * Do we have a valid private record? |
| 15028 | */ |
| 15029 | if (!dns_nsec3param_fromprivate(&private, &rdata, |
| 15030 | buf, sizeof(buf))) |
| 15031 | continue; |
| 15032 | |
| 15033 | /* |
| 15034 | * Remove any NSEC3PARAM records scheduled to be removed. |
| 15035 | */ |
| 15036 | if (NSEC3REMOVE(rdata.data[1])) { |
| 15037 | /* |
| 15038 | * Zero out the flags. |
| 15039 | */ |
| 15040 | rdata.data[1] = 0; |
| 15041 | |
| 15042 | for (nsec3p = ISC_LIST_HEAD(*nsec3list); |
| 15043 | nsec3p != NULL; |
| 15044 | nsec3p = next) |
| 15045 | { |
| 15046 | next = ISC_LIST_NEXT(nsec3p, link); |
| 15047 | |
| 15048 | if (nsec3p->length == rdata.length + 1 && |
| 15049 | memcmp(rdata.data, nsec3p->data + 1, |
| 15050 | nsec3p->length - 1) == 0) { |
| 15051 | ISC_LIST_UNLINK(*nsec3list, |
| 15052 | nsec3p, link); |
| 15053 | isc_mem_put(zone->mctx, nsec3p, |
| 15054 | sizeof(nsec3param_t)); |
| 15055 | } |
| 15056 | } |
| 15057 | continue; |
| 15058 | } |
| 15059 | |
| 15060 | nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t)); |
| 15061 | if (nsec3param == NULL) |
| 15062 | CHECK(ISC_R_NOMEMORY); |
| 15063 | ISC_LINK_INIT(nsec3param, link); |
| 15064 | |
| 15065 | /* |
| 15066 | * Copy the remaining private records so the nsec/nsec3 |
| 15067 | * chain gets created. |
| 15068 | */ |
| 15069 | INSIST(private.length <= sizeof(nsec3param->data)); |
| 15070 | memmove(nsec3param->data, private.data, private.length); |
| 15071 | nsec3param->length = private.length; |
| 15072 | ISC_LIST_APPEND(*nsec3list, nsec3param, link); |
| 15073 | } |
| 15074 | |
| 15075 | done: |
| 15076 | if (result == ISC_R_NOMORE || result == ISC_R_NOTFOUND) |
| 15077 | result = ISC_R_SUCCESS; |
| 15078 | |
| 15079 | failure: |
| 15080 | if (node != NULL) |
| 15081 | dns_db_detachnode(db, &node); |
| 15082 | if (version != NULL) |
| 15083 | dns_db_closeversion(db, &version, false); |
| 15084 | if (db != NULL) |
| 15085 | dns_db_detach(&db); |
| 15086 | if (dns_rdataset_isassociated(&rdataset)) |
| 15087 | dns_rdataset_disassociate(&rdataset); |
| 15088 | if (dns_rdataset_isassociated(&prdataset)) |
| 15089 | dns_rdataset_disassociate(&prdataset); |
| 15090 | return (result); |
| 15091 | } |
| 15092 | |
| 15093 | /* |
| 15094 | * Populate new zone db with private type records found by save_nsec3param(). |
| 15095 | */ |
| 15096 | static isc_result_t |
| 15097 | restore_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, |
| 15098 | nsec3paramlist_t *nsec3list) |
| 15099 | { |
| 15100 | isc_result_t result; |
| 15101 | dns_diff_t diff; |
| 15102 | dns_rdata_t rdata; |
| 15103 | nsec3param_t *nsec3p = NULL; |
| 15104 | nsec3param_t *next; |
| 15105 | |
| 15106 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15107 | REQUIRE(!ISC_LIST_EMPTY(*nsec3list)); |
| 15108 | |
| 15109 | dns_diff_init(zone->mctx, &diff); |
| 15110 | |
| 15111 | /* |
| 15112 | * Loop through the list of private-type records, set the INITIAL |
| 15113 | * and CREATE flags, and the add the record to the apex of the tree |
| 15114 | * in db. |
| 15115 | */ |
| 15116 | for (nsec3p = ISC_LIST_HEAD(*nsec3list); |
| 15117 | nsec3p != NULL; |
| 15118 | nsec3p = next) |
| 15119 | { |
| 15120 | next = ISC_LIST_NEXT(nsec3p, link); |
| 15121 | dns_rdata_init(&rdata); |
| 15122 | nsec3p->data[2] = DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_INITIAL; |
| 15123 | rdata.length = nsec3p->length; |
| 15124 | rdata.data = nsec3p->data; |
| 15125 | rdata.type = zone->privatetype; |
| 15126 | rdata.rdclass = zone->rdclass; |
| 15127 | result = update_one_rr(db, version, &diff, DNS_DIFFOP_ADD, |
| 15128 | &zone->origin, 0, &rdata); |
| 15129 | if (result != ISC_R_SUCCESS) { |
| 15130 | break; |
| 15131 | } |
| 15132 | } |
| 15133 | |
| 15134 | dns_diff_clear(&diff); |
| 15135 | return (result); |
| 15136 | } |
| 15137 | |
| 15138 | static void |
| 15139 | receive_secure_db(isc_task_t *task, isc_event_t *event) { |
| 15140 | isc_result_t result; |
| 15141 | dns_zone_t *zone; |
| 15142 | dns_db_t *rawdb, *db = NULL; |
| 15143 | dns_dbnode_t *rawnode = NULL, *node = NULL; |
| 15144 | dns_fixedname_t fname; |
| 15145 | dns_name_t *name; |
| 15146 | dns_dbiterator_t *dbiterator = NULL; |
| 15147 | dns_rdatasetiter_t *rdsit = NULL; |
| 15148 | dns_rdataset_t rdataset; |
| 15149 | dns_dbversion_t *version = NULL; |
| 15150 | isc_time_t loadtime; |
| 15151 | unsigned int oldserial = 0; |
| 15152 | bool have_oldserial = false; |
| 15153 | nsec3paramlist_t nsec3list; |
| 15154 | isc_event_t *setnsec3param_event; |
| 15155 | dns_zone_t *dummy; |
| 15156 | |
| 15157 | UNUSED(task); |
| 15158 | |
| 15159 | ISC_LIST_INIT(nsec3list); |
| 15160 | |
| 15161 | zone = event->ev_arg; |
| 15162 | rawdb = ((struct secure_event *)event)->db; |
| 15163 | isc_event_free(&event); |
| 15164 | |
| 15165 | name = dns_fixedname_initname(&fname); |
| 15166 | dns_rdataset_init(&rdataset); |
| 15167 | |
| 15168 | LOCK_ZONE(zone); |
| 15169 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || !inline_secure(zone)) { |
| 15170 | result = ISC_R_SHUTTINGDOWN; |
| 15171 | goto failure; |
| 15172 | } |
| 15173 | |
| 15174 | TIME_NOW(&loadtime); |
| 15175 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 15176 | if (zone->db != NULL) { |
| 15177 | result = dns_db_getsoaserial(zone->db, NULL, &oldserial); |
| 15178 | if (result == ISC_R_SUCCESS) |
| 15179 | have_oldserial = true; |
| 15180 | |
| 15181 | /* |
| 15182 | * assemble nsec3parameters from the old zone, and set a flag |
| 15183 | * if any are found |
| 15184 | */ |
| 15185 | result = save_nsec3param(zone, &nsec3list); |
| 15186 | if (result != ISC_R_SUCCESS) { |
| 15187 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 15188 | goto failure; |
| 15189 | } |
| 15190 | } |
| 15191 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 15192 | |
| 15193 | result = dns_db_create(zone->mctx, zone->db_argv[0], |
| 15194 | &zone->origin, dns_dbtype_zone, zone->rdclass, |
| 15195 | zone->db_argc - 1, zone->db_argv + 1, &db); |
| 15196 | if (result != ISC_R_SUCCESS) |
| 15197 | goto failure; |
| 15198 | |
| 15199 | result = dns_db_setgluecachestats(db, zone->gluecachestats); |
| 15200 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) { |
| 15201 | goto failure; |
| 15202 | } |
| 15203 | |
| 15204 | result = dns_db_newversion(db, &version); |
| 15205 | if (result != ISC_R_SUCCESS) |
| 15206 | goto failure; |
| 15207 | |
| 15208 | result = dns_db_createiterator(rawdb, 0, &dbiterator); |
| 15209 | if (result != ISC_R_SUCCESS) |
| 15210 | goto failure; |
| 15211 | |
| 15212 | for (result = dns_dbiterator_first(dbiterator); |
| 15213 | result == ISC_R_SUCCESS; |
| 15214 | result = dns_dbiterator_next(dbiterator)) { |
| 15215 | result = dns_dbiterator_current(dbiterator, &rawnode, name); |
| 15216 | if (result != ISC_R_SUCCESS) |
| 15217 | continue; |
| 15218 | |
| 15219 | result = dns_db_findnode(db, name, true, &node); |
| 15220 | if (result != ISC_R_SUCCESS) |
| 15221 | goto failure; |
| 15222 | |
| 15223 | result = dns_db_allrdatasets(rawdb, rawnode, NULL, 0, &rdsit); |
| 15224 | if (result != ISC_R_SUCCESS) |
| 15225 | goto failure; |
| 15226 | |
| 15227 | for (result = dns_rdatasetiter_first(rdsit); |
| 15228 | result == ISC_R_SUCCESS; |
| 15229 | result = dns_rdatasetiter_next(rdsit)) { |
| 15230 | dns_rdatasetiter_current(rdsit, &rdataset); |
| 15231 | if (rdataset.type == dns_rdatatype_nsec || |
| 15232 | rdataset.type == dns_rdatatype_rrsig || |
| 15233 | rdataset.type == dns_rdatatype_nsec3 || |
| 15234 | rdataset.type == dns_rdatatype_dnskey || |
| 15235 | rdataset.type == dns_rdatatype_nsec3param) { |
| 15236 | dns_rdataset_disassociate(&rdataset); |
| 15237 | continue; |
| 15238 | } |
| 15239 | if (rdataset.type == dns_rdatatype_soa && |
| 15240 | have_oldserial) { |
| 15241 | result = checkandaddsoa(db, node, version, |
| 15242 | &rdataset, oldserial); |
| 15243 | } else |
| 15244 | result = dns_db_addrdataset(db, node, version, |
| 15245 | 0, &rdataset, 0, |
| 15246 | NULL); |
| 15247 | if (result != ISC_R_SUCCESS) |
| 15248 | goto failure; |
| 15249 | |
| 15250 | dns_rdataset_disassociate(&rdataset); |
| 15251 | } |
| 15252 | dns_rdatasetiter_destroy(&rdsit); |
| 15253 | dns_db_detachnode(rawdb, &rawnode); |
| 15254 | dns_db_detachnode(db, &node); |
| 15255 | } |
| 15256 | |
| 15257 | /* |
| 15258 | * Call restore_nsec3param() to create private-type records from |
| 15259 | * the old nsec3 parameters and insert them into db |
| 15260 | */ |
| 15261 | if (!ISC_LIST_EMPTY(nsec3list)) { |
| 15262 | result = restore_nsec3param(zone, db, version, &nsec3list); |
| 15263 | if (result != ISC_R_SUCCESS) { |
| 15264 | goto failure; |
| 15265 | } |
| 15266 | } |
| 15267 | |
| 15268 | dns_db_closeversion(db, &version, true); |
| 15269 | |
| 15270 | /* |
| 15271 | * Lock hierarchy: zmgr, zone, raw. |
| 15272 | */ |
| 15273 | INSIST(zone != zone->raw); |
| 15274 | LOCK_ZONE(zone->raw); |
| 15275 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 15276 | result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS); |
| 15277 | zone_needdump(zone, 0); /* XXXMPA */ |
| 15278 | UNLOCK_ZONE(zone->raw); |
| 15279 | |
| 15280 | /* |
| 15281 | * Process any queued NSEC3PARAM change requests. |
| 15282 | */ |
| 15283 | while (!ISC_LIST_EMPTY(zone->setnsec3param_queue)) { |
| 15284 | setnsec3param_event = ISC_LIST_HEAD(zone->setnsec3param_queue); |
| 15285 | ISC_LIST_UNLINK(zone->setnsec3param_queue, setnsec3param_event, |
| 15286 | ev_link); |
| 15287 | dummy = NULL; |
| 15288 | zone_iattach(zone, &dummy); |
| 15289 | isc_task_send(zone->task, &setnsec3param_event); |
| 15290 | } |
| 15291 | |
| 15292 | failure: |
| 15293 | UNLOCK_ZONE(zone); |
| 15294 | if (result != ISC_R_SUCCESS) |
| 15295 | dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_db: %s" , |
| 15296 | dns_result_totext(result)); |
| 15297 | |
| 15298 | while (!ISC_LIST_EMPTY(nsec3list)) { |
| 15299 | nsec3param_t *nsec3p; |
| 15300 | nsec3p = ISC_LIST_HEAD(nsec3list); |
| 15301 | ISC_LIST_UNLINK(nsec3list, nsec3p, link); |
| 15302 | isc_mem_put(zone->mctx, nsec3p, sizeof(nsec3param_t)); |
| 15303 | } |
| 15304 | if (dns_rdataset_isassociated(&rdataset)) |
| 15305 | dns_rdataset_disassociate(&rdataset); |
| 15306 | if (db != NULL) { |
| 15307 | if (node != NULL) |
| 15308 | dns_db_detachnode(db, &node); |
| 15309 | if (version != NULL) |
| 15310 | dns_db_closeversion(db, &version, false); |
| 15311 | dns_db_detach(&db); |
| 15312 | } |
| 15313 | if (rawnode != NULL) |
| 15314 | dns_db_detachnode(rawdb, &rawnode); |
| 15315 | dns_db_detach(&rawdb); |
| 15316 | if (dbiterator != NULL) |
| 15317 | dns_dbiterator_destroy(&dbiterator); |
| 15318 | dns_zone_idetach(&zone); |
| 15319 | |
| 15320 | INSIST(version == NULL); |
| 15321 | } |
| 15322 | |
| 15323 | static isc_result_t |
| 15324 | zone_send_securedb(dns_zone_t *zone, dns_db_t *db) { |
| 15325 | isc_event_t *e; |
| 15326 | dns_db_t *dummy = NULL; |
| 15327 | dns_zone_t *secure = NULL; |
| 15328 | |
| 15329 | e = isc_event_allocate(zone->secure->mctx, zone, |
| 15330 | DNS_EVENT_ZONESECUREDB, |
| 15331 | receive_secure_db, zone->secure, |
| 15332 | sizeof(struct secure_event)); |
| 15333 | if (e == NULL) |
| 15334 | return (ISC_R_NOMEMORY); |
| 15335 | dns_db_attach(db, &dummy); |
| 15336 | ((struct secure_event *)e)->db = dummy; |
| 15337 | INSIST(LOCKED_ZONE(zone->secure)); |
| 15338 | zone_iattach(zone->secure, &secure); |
| 15339 | isc_task_send(zone->secure->task, &e); |
| 15340 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE); |
| 15341 | return (ISC_R_SUCCESS); |
| 15342 | } |
| 15343 | |
| 15344 | isc_result_t |
| 15345 | dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) { |
| 15346 | isc_result_t result; |
| 15347 | dns_zone_t *secure = NULL; |
| 15348 | |
| 15349 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15350 | again: |
| 15351 | LOCK_ZONE(zone); |
| 15352 | if (inline_raw(zone)) { |
| 15353 | secure = zone->secure; |
| 15354 | INSIST(secure != zone); |
| 15355 | TRYLOCK_ZONE(result, secure); |
| 15356 | if (result != ISC_R_SUCCESS) { |
| 15357 | UNLOCK_ZONE(zone); |
| 15358 | secure = NULL; |
| 15359 | isc_thread_yield(); |
| 15360 | goto again; |
| 15361 | } |
| 15362 | } |
| 15363 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); |
| 15364 | result = zone_replacedb(zone, db, dump); |
| 15365 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
| 15366 | if (secure != NULL) |
| 15367 | UNLOCK_ZONE(secure); |
| 15368 | UNLOCK_ZONE(zone); |
| 15369 | return (result); |
| 15370 | } |
| 15371 | |
| 15372 | static isc_result_t |
| 15373 | zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) { |
| 15374 | dns_dbversion_t *ver; |
| 15375 | isc_result_t result; |
| 15376 | unsigned int soacount = 0; |
| 15377 | unsigned int nscount = 0; |
| 15378 | |
| 15379 | /* |
| 15380 | * 'zone' and 'zone->db' locked by caller. |
| 15381 | */ |
| 15382 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15383 | REQUIRE(LOCKED_ZONE(zone)); |
| 15384 | if (inline_raw(zone)) |
| 15385 | REQUIRE(LOCKED_ZONE(zone->secure)); |
| 15386 | |
| 15387 | result = zone_get_from_db(zone, db, &nscount, &soacount, |
| 15388 | NULL, NULL, NULL, NULL, NULL, NULL); |
| 15389 | if (result == ISC_R_SUCCESS) { |
| 15390 | if (soacount != 1) { |
| 15391 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15392 | "has %d SOA records" , soacount); |
| 15393 | result = DNS_R_BADZONE; |
| 15394 | } |
| 15395 | if (nscount == 0 && zone->type != dns_zone_key) { |
| 15396 | dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records" ); |
| 15397 | result = DNS_R_BADZONE; |
| 15398 | } |
| 15399 | if (result != ISC_R_SUCCESS) |
| 15400 | return (result); |
| 15401 | } else { |
| 15402 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15403 | "retrieving SOA and NS records failed: %s" , |
| 15404 | dns_result_totext(result)); |
| 15405 | return (result); |
| 15406 | } |
| 15407 | |
| 15408 | result = check_nsec3param(zone, db); |
| 15409 | if (result != ISC_R_SUCCESS) |
| 15410 | return (result); |
| 15411 | |
| 15412 | ver = NULL; |
| 15413 | dns_db_currentversion(db, &ver); |
| 15414 | |
| 15415 | /* |
| 15416 | * The initial version of a slave zone is always dumped; |
| 15417 | * subsequent versions may be journaled instead if this |
| 15418 | * is enabled in the configuration. |
| 15419 | */ |
| 15420 | if (zone->db != NULL && zone->journal != NULL && |
| 15421 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && |
| 15422 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) |
| 15423 | { |
| 15424 | uint32_t serial, oldserial; |
| 15425 | |
| 15426 | dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs" ); |
| 15427 | |
| 15428 | result = dns_db_getsoaserial(db, ver, &serial); |
| 15429 | if (result != ISC_R_SUCCESS) { |
| 15430 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15431 | "ixfr-from-differences: unable to get " |
| 15432 | "new serial" ); |
| 15433 | goto fail; |
| 15434 | } |
| 15435 | |
| 15436 | /* |
| 15437 | * This is checked in zone_postload() for master zones. |
| 15438 | */ |
| 15439 | result = zone_get_from_db(zone, zone->db, NULL, &soacount, |
| 15440 | &oldserial, NULL, NULL, NULL, NULL, |
| 15441 | NULL); |
| 15442 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 15443 | RUNTIME_CHECK(soacount > 0U); |
| 15444 | if ((zone->type == dns_zone_slave || |
| 15445 | (zone->type == dns_zone_redirect && |
| 15446 | zone->masters != NULL)) |
| 15447 | && !isc_serial_gt(serial, oldserial)) { |
| 15448 | uint32_t serialmin, serialmax; |
| 15449 | serialmin = (oldserial + 1) & 0xffffffffU; |
| 15450 | serialmax = (oldserial + 0x7fffffffU) & 0xffffffffU; |
| 15451 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15452 | "ixfr-from-differences: failed: " |
| 15453 | "new serial (%u) out of range [%u - %u]" , |
| 15454 | serial, serialmin, serialmax); |
| 15455 | result = ISC_R_RANGE; |
| 15456 | goto fail; |
| 15457 | } |
| 15458 | |
| 15459 | result = dns_db_diff(zone->mctx, db, ver, zone->db, NULL, |
| 15460 | zone->journal); |
| 15461 | if (result != ISC_R_SUCCESS) { |
| 15462 | char strbuf[ISC_STRERRORSIZE]; |
| 15463 | strerror_r(errno, strbuf, sizeof(strbuf)); |
| 15464 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15465 | "ixfr-from-differences: failed: " |
| 15466 | "%s" , strbuf); |
| 15467 | goto fallback; |
| 15468 | } |
| 15469 | if (dump) |
| 15470 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 15471 | else |
| 15472 | zone_journal_compact(zone, zone->db, serial); |
| 15473 | if (zone->type == dns_zone_master && inline_raw(zone)) |
| 15474 | zone_send_secureserial(zone, serial); |
| 15475 | } else { |
| 15476 | fallback: |
| 15477 | if (dump && zone->masterfile != NULL) { |
| 15478 | /* |
| 15479 | * If DNS_ZONEFLG_FORCEXFER was set we don't want |
| 15480 | * to keep the old masterfile. |
| 15481 | */ |
| 15482 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) && |
| 15483 | remove(zone->masterfile) < 0 && errno != ENOENT) { |
| 15484 | char strbuf[ISC_STRERRORSIZE]; |
| 15485 | strerror_r(errno, strbuf, sizeof(strbuf)); |
| 15486 | isc_log_write(dns_lctx, |
| 15487 | DNS_LOGCATEGORY_GENERAL, |
| 15488 | DNS_LOGMODULE_ZONE, |
| 15489 | ISC_LOG_WARNING, |
| 15490 | "unable to remove masterfile " |
| 15491 | "'%s': '%s'" , |
| 15492 | zone->masterfile, strbuf); |
| 15493 | } |
| 15494 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) == 0) |
| 15495 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NODELAY); |
| 15496 | else |
| 15497 | zone_needdump(zone, 0); |
| 15498 | } |
| 15499 | if (dump && zone->journal != NULL) { |
| 15500 | /* |
| 15501 | * The in-memory database just changed, and |
| 15502 | * because 'dump' is set, it didn't change by |
| 15503 | * being loaded from disk. Also, we have not |
| 15504 | * journaled diffs for this change. |
| 15505 | * Therefore, the on-disk journal is missing |
| 15506 | * the deltas for this change. Since it can |
| 15507 | * no longer be used to bring the zone |
| 15508 | * up-to-date, it is useless and should be |
| 15509 | * removed. |
| 15510 | */ |
| 15511 | isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, |
| 15512 | DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), |
| 15513 | "removing journal file" ); |
| 15514 | if (remove(zone->journal) < 0 && errno != ENOENT) { |
| 15515 | char strbuf[ISC_STRERRORSIZE]; |
| 15516 | strerror_r(errno, strbuf, sizeof(strbuf)); |
| 15517 | isc_log_write(dns_lctx, |
| 15518 | DNS_LOGCATEGORY_GENERAL, |
| 15519 | DNS_LOGMODULE_ZONE, |
| 15520 | ISC_LOG_WARNING, |
| 15521 | "unable to remove journal " |
| 15522 | "'%s': '%s'" , |
| 15523 | zone->journal, strbuf); |
| 15524 | } |
| 15525 | } |
| 15526 | |
| 15527 | if (inline_raw(zone)) |
| 15528 | zone_send_securedb(zone, db); |
| 15529 | } |
| 15530 | |
| 15531 | dns_db_closeversion(db, &ver, false); |
| 15532 | |
| 15533 | dns_zone_log(zone, ISC_LOG_DEBUG(3), "replacing zone database" ); |
| 15534 | |
| 15535 | if (zone->db != NULL) |
| 15536 | zone_detachdb(zone); |
| 15537 | zone_attachdb(zone, db); |
| 15538 | dns_db_settask(zone->db, zone->task); |
| 15539 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY); |
| 15540 | return (ISC_R_SUCCESS); |
| 15541 | |
| 15542 | fail: |
| 15543 | dns_db_closeversion(db, &ver, false); |
| 15544 | return (result); |
| 15545 | } |
| 15546 | |
| 15547 | /* The caller must hold the dblock as a writer. */ |
| 15548 | static inline void |
| 15549 | zone_attachdb(dns_zone_t *zone, dns_db_t *db) { |
| 15550 | REQUIRE(zone->db == NULL && db != NULL); |
| 15551 | |
| 15552 | dns_db_attach(db, &zone->db); |
| 15553 | } |
| 15554 | |
| 15555 | /* The caller must hold the dblock as a writer. */ |
| 15556 | static inline void |
| 15557 | zone_detachdb(dns_zone_t *zone) { |
| 15558 | REQUIRE(zone->db != NULL); |
| 15559 | |
| 15560 | dns_db_detach(&zone->db); |
| 15561 | } |
| 15562 | |
| 15563 | static void |
| 15564 | zone_xfrdone(dns_zone_t *zone, isc_result_t result) { |
| 15565 | isc_time_t now; |
| 15566 | bool again = false; |
| 15567 | unsigned int soacount; |
| 15568 | unsigned int nscount; |
| 15569 | uint32_t serial, refresh, retry, expire, minimum; |
| 15570 | isc_result_t xfrresult = result; |
| 15571 | bool free_needed; |
| 15572 | dns_zone_t *secure = NULL; |
| 15573 | |
| 15574 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15575 | |
| 15576 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 15577 | "zone transfer finished: %s" , dns_result_totext(result)); |
| 15578 | |
| 15579 | /* |
| 15580 | * Obtaining a lock on the zone->secure (see zone_send_secureserial) |
| 15581 | * could result in a deadlock due to a LOR so we will spin if we |
| 15582 | * can't obtain the both locks. |
| 15583 | */ |
| 15584 | again: |
| 15585 | LOCK_ZONE(zone); |
| 15586 | if (inline_raw(zone)) { |
| 15587 | secure = zone->secure; |
| 15588 | INSIST(secure != zone); |
| 15589 | TRYLOCK_ZONE(result, secure); |
| 15590 | if (result != ISC_R_SUCCESS) { |
| 15591 | UNLOCK_ZONE(zone); |
| 15592 | secure = NULL; |
| 15593 | isc_thread_yield(); |
| 15594 | goto again; |
| 15595 | } |
| 15596 | } |
| 15597 | |
| 15598 | INSIST((zone->flags & DNS_ZONEFLG_REFRESH) != 0); |
| 15599 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 15600 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); |
| 15601 | |
| 15602 | TIME_NOW(&now); |
| 15603 | switch (xfrresult) { |
| 15604 | case ISC_R_SUCCESS: |
| 15605 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 15606 | /* FALLTHROUGH */ |
| 15607 | case DNS_R_UPTODATE: |
| 15608 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FORCEXFER); |
| 15609 | /* |
| 15610 | * Has the zone expired underneath us? |
| 15611 | */ |
| 15612 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 15613 | if (zone->db == NULL) { |
| 15614 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 15615 | goto same_master; |
| 15616 | } |
| 15617 | |
| 15618 | /* |
| 15619 | * Update the zone structure's data from the actual |
| 15620 | * SOA received. |
| 15621 | */ |
| 15622 | nscount = 0; |
| 15623 | soacount = 0; |
| 15624 | INSIST(zone->db != NULL); |
| 15625 | result = zone_get_from_db(zone, zone->db, &nscount, |
| 15626 | &soacount, &serial, &refresh, |
| 15627 | &retry, &expire, &minimum, NULL); |
| 15628 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 15629 | if (result == ISC_R_SUCCESS) { |
| 15630 | if (soacount != 1) |
| 15631 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15632 | "transferred zone " |
| 15633 | "has %d SOA record%s" , soacount, |
| 15634 | (soacount != 0) ? "s" : "" ); |
| 15635 | if (nscount == 0) { |
| 15636 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15637 | "transferred zone " |
| 15638 | "has no NS records" ); |
| 15639 | if (DNS_ZONE_FLAG(zone, |
| 15640 | DNS_ZONEFLG_HAVETIMERS)) { |
| 15641 | zone->refresh = DNS_ZONE_DEFAULTREFRESH; |
| 15642 | zone->retry = DNS_ZONE_DEFAULTRETRY; |
| 15643 | } |
| 15644 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS); |
| 15645 | zone_unload(zone); |
| 15646 | goto next_master; |
| 15647 | } |
| 15648 | zone->refresh = RANGE(refresh, zone->minrefresh, |
| 15649 | zone->maxrefresh); |
| 15650 | zone->retry = RANGE(retry, zone->minretry, |
| 15651 | zone->maxretry); |
| 15652 | zone->expire = RANGE(expire, |
| 15653 | zone->refresh + zone->retry, |
| 15654 | DNS_MAX_EXPIRE); |
| 15655 | zone->minimum = minimum; |
| 15656 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); |
| 15657 | } |
| 15658 | |
| 15659 | /* |
| 15660 | * Set our next update/expire times. |
| 15661 | */ |
| 15662 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) { |
| 15663 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); |
| 15664 | zone->refreshtime = now; |
| 15665 | DNS_ZONE_TIME_ADD(&now, zone->expire, |
| 15666 | &zone->expiretime); |
| 15667 | } else { |
| 15668 | DNS_ZONE_JITTER_ADD(&now, zone->refresh, |
| 15669 | &zone->refreshtime); |
| 15670 | DNS_ZONE_TIME_ADD(&now, zone->expire, |
| 15671 | &zone->expiretime); |
| 15672 | } |
| 15673 | if (result == ISC_R_SUCCESS && xfrresult == ISC_R_SUCCESS) { |
| 15674 | char buf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''" )]; |
| 15675 | if (zone->tsigkey != NULL) { |
| 15676 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 15677 | dns_name_format(&zone->tsigkey->name, namebuf, |
| 15678 | sizeof(namebuf)); |
| 15679 | snprintf(buf, sizeof(buf), ": TSIG '%s'" , |
| 15680 | namebuf); |
| 15681 | } else |
| 15682 | buf[0] = '\0'; |
| 15683 | dns_zone_log(zone, ISC_LOG_INFO, |
| 15684 | "transferred serial %u%s" , |
| 15685 | serial, buf); |
| 15686 | if (inline_raw(zone)) |
| 15687 | zone_send_secureserial(zone, serial); |
| 15688 | } |
| 15689 | |
| 15690 | /* |
| 15691 | * This is not necessary if we just performed a AXFR |
| 15692 | * however it is necessary for an IXFR / UPTODATE and |
| 15693 | * won't hurt with an AXFR. |
| 15694 | */ |
| 15695 | if (zone->masterfile != NULL || zone->journal != NULL) { |
| 15696 | unsigned int delay = DNS_DUMP_DELAY; |
| 15697 | |
| 15698 | result = ISC_R_FAILURE; |
| 15699 | if (zone->journal != NULL) |
| 15700 | result = isc_file_settime(zone->journal, &now); |
| 15701 | if (result != ISC_R_SUCCESS && |
| 15702 | zone->masterfile != NULL) |
| 15703 | result = isc_file_settime(zone->masterfile, |
| 15704 | &now); |
| 15705 | |
| 15706 | if ((DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NODELAY) != 0) || |
| 15707 | result == ISC_R_FILENOTFOUND) |
| 15708 | delay = 0; |
| 15709 | |
| 15710 | if ((result == ISC_R_SUCCESS || |
| 15711 | result == ISC_R_FILENOTFOUND) && |
| 15712 | zone->masterfile != NULL) |
| 15713 | zone_needdump(zone, delay); |
| 15714 | else if (result != ISC_R_SUCCESS) |
| 15715 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 15716 | "transfer: could not set file " |
| 15717 | "modification time of '%s': %s" , |
| 15718 | zone->masterfile, |
| 15719 | dns_result_totext(result)); |
| 15720 | } |
| 15721 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NODELAY); |
| 15722 | inc_stats(zone, dns_zonestatscounter_xfrsuccess); |
| 15723 | break; |
| 15724 | |
| 15725 | case DNS_R_BADIXFR: |
| 15726 | /* Force retry with AXFR. */ |
| 15727 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLAG_NOIXFR); |
| 15728 | goto same_master; |
| 15729 | |
| 15730 | case DNS_R_TOOMANYRECORDS: |
| 15731 | case DNS_R_VERIFYFAILURE: |
| 15732 | DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); |
| 15733 | inc_stats(zone, dns_zonestatscounter_xfrfail); |
| 15734 | break; |
| 15735 | |
| 15736 | default: |
| 15737 | next_master: |
| 15738 | /* |
| 15739 | * Skip to next failed / untried master. |
| 15740 | */ |
| 15741 | do { |
| 15742 | zone->curmaster++; |
| 15743 | } while (zone->curmaster < zone->masterscnt && |
| 15744 | zone->mastersok[zone->curmaster]); |
| 15745 | /* FALLTHROUGH */ |
| 15746 | same_master: |
| 15747 | if (zone->curmaster >= zone->masterscnt) { |
| 15748 | zone->curmaster = 0; |
| 15749 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && |
| 15750 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { |
| 15751 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 15752 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); |
| 15753 | while (zone->curmaster < zone->masterscnt && |
| 15754 | zone->mastersok[zone->curmaster]) |
| 15755 | zone->curmaster++; |
| 15756 | again = true; |
| 15757 | } else |
| 15758 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); |
| 15759 | } else { |
| 15760 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); |
| 15761 | again = true; |
| 15762 | } |
| 15763 | inc_stats(zone, dns_zonestatscounter_xfrfail); |
| 15764 | break; |
| 15765 | } |
| 15766 | zone_settimer(zone, &now); |
| 15767 | |
| 15768 | /* |
| 15769 | * If creating the transfer object failed, zone->xfr is NULL. |
| 15770 | * Otherwise, we are called as the done callback of a zone |
| 15771 | * transfer object that just entered its shutting-down |
| 15772 | * state. Since we are no longer responsible for shutting |
| 15773 | * it down, we can detach our reference. |
| 15774 | */ |
| 15775 | if (zone->xfr != NULL) |
| 15776 | dns_xfrin_detach(&zone->xfr); |
| 15777 | |
| 15778 | if (zone->tsigkey != NULL) |
| 15779 | dns_tsigkey_detach(&zone->tsigkey); |
| 15780 | |
| 15781 | /* |
| 15782 | * Handle any deferred journal compaction. |
| 15783 | */ |
| 15784 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDCOMPACT)) { |
| 15785 | dns_db_t *db = NULL; |
| 15786 | if (dns_zone_getdb(zone, &db) == ISC_R_SUCCESS) { |
| 15787 | zone_journal_compact(zone, db, zone->compact_serial); |
| 15788 | dns_db_detach(&db); |
| 15789 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT); |
| 15790 | } |
| 15791 | } |
| 15792 | |
| 15793 | if (secure != NULL) |
| 15794 | UNLOCK_ZONE(secure); |
| 15795 | /* |
| 15796 | * This transfer finishing freed up a transfer quota slot. |
| 15797 | * Let any other zones waiting for quota have it. |
| 15798 | */ |
| 15799 | if (zone->zmgr != NULL && |
| 15800 | zone->statelist == &zone->zmgr->xfrin_in_progress) { |
| 15801 | UNLOCK_ZONE(zone); |
| 15802 | RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); |
| 15803 | ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink); |
| 15804 | zone->statelist = NULL; |
| 15805 | zmgr_resume_xfrs(zone->zmgr, false); |
| 15806 | RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); |
| 15807 | LOCK_ZONE(zone); |
| 15808 | } |
| 15809 | |
| 15810 | /* |
| 15811 | * Retry with a different server if necessary. |
| 15812 | */ |
| 15813 | if (again && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) |
| 15814 | queue_soa_query(zone); |
| 15815 | |
| 15816 | INSIST(zone->irefs > 0); |
| 15817 | zone->irefs--; |
| 15818 | free_needed = exit_check(zone); |
| 15819 | UNLOCK_ZONE(zone); |
| 15820 | if (free_needed) |
| 15821 | zone_free(zone); |
| 15822 | } |
| 15823 | |
| 15824 | static void |
| 15825 | zone_loaddone(void *arg, isc_result_t result) { |
| 15826 | static char me[] = "zone_loaddone" ; |
| 15827 | dns_load_t *load = arg; |
| 15828 | dns_zone_t *zone; |
| 15829 | isc_result_t tresult; |
| 15830 | dns_zone_t *secure = NULL; |
| 15831 | |
| 15832 | REQUIRE(DNS_LOAD_VALID(load)); |
| 15833 | zone = load->zone; |
| 15834 | |
| 15835 | ENTER; |
| 15836 | |
| 15837 | /* |
| 15838 | * If zone loading failed, remove the update db callbacks prior |
| 15839 | * to calling the list of callbacks in the zone load structure. |
| 15840 | */ |
| 15841 | if (result != ISC_R_SUCCESS) { |
| 15842 | dns_zone_rpz_disable_db(zone, load->db); |
| 15843 | dns_zone_catz_disable_db(zone, load->db); |
| 15844 | } |
| 15845 | |
| 15846 | tresult = dns_db_endload(load->db, &load->callbacks); |
| 15847 | if (tresult != ISC_R_SUCCESS && |
| 15848 | (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE)) |
| 15849 | result = tresult; |
| 15850 | |
| 15851 | /* |
| 15852 | * Lock hierarchy: zmgr, zone, raw. |
| 15853 | */ |
| 15854 | again: |
| 15855 | LOCK_ZONE(zone); |
| 15856 | INSIST(zone != zone->raw); |
| 15857 | if (inline_secure(zone)) |
| 15858 | LOCK_ZONE(zone->raw); |
| 15859 | else if (inline_raw(zone)) { |
| 15860 | secure = zone->secure; |
| 15861 | TRYLOCK_ZONE(result, secure); |
| 15862 | if (result != ISC_R_SUCCESS) { |
| 15863 | UNLOCK_ZONE(zone); |
| 15864 | secure = NULL; |
| 15865 | isc_thread_yield(); |
| 15866 | goto again; |
| 15867 | } |
| 15868 | } |
| 15869 | (void)zone_postload(zone, load->db, load->loadtime, result); |
| 15870 | zonemgr_putio(&zone->readio); |
| 15871 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADING); |
| 15872 | zone_idetach(&load->callbacks.zone); |
| 15873 | /* |
| 15874 | * Leave the zone frozen if the reload fails. |
| 15875 | */ |
| 15876 | if ((result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) && |
| 15877 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_THAW)) |
| 15878 | zone->update_disabled = false; |
| 15879 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_THAW); |
| 15880 | if (inline_secure(zone)) |
| 15881 | UNLOCK_ZONE(zone->raw); |
| 15882 | else if (secure != NULL) |
| 15883 | UNLOCK_ZONE(secure); |
| 15884 | UNLOCK_ZONE(zone); |
| 15885 | |
| 15886 | load->magic = 0; |
| 15887 | dns_db_detach(&load->db); |
| 15888 | if (load->zone->lctx != NULL) |
| 15889 | dns_loadctx_detach(&load->zone->lctx); |
| 15890 | dns_zone_idetach(&load->zone); |
| 15891 | isc_mem_putanddetach(&load->mctx, load, sizeof(*load)); |
| 15892 | } |
| 15893 | |
| 15894 | void |
| 15895 | dns_zone_getssutable(dns_zone_t *zone, dns_ssutable_t **table) { |
| 15896 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15897 | REQUIRE(table != NULL); |
| 15898 | REQUIRE(*table == NULL); |
| 15899 | |
| 15900 | LOCK_ZONE(zone); |
| 15901 | if (zone->ssutable != NULL) |
| 15902 | dns_ssutable_attach(zone->ssutable, table); |
| 15903 | UNLOCK_ZONE(zone); |
| 15904 | } |
| 15905 | |
| 15906 | void |
| 15907 | dns_zone_setssutable(dns_zone_t *zone, dns_ssutable_t *table) { |
| 15908 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15909 | |
| 15910 | LOCK_ZONE(zone); |
| 15911 | if (zone->ssutable != NULL) |
| 15912 | dns_ssutable_detach(&zone->ssutable); |
| 15913 | if (table != NULL) |
| 15914 | dns_ssutable_attach(table, &zone->ssutable); |
| 15915 | UNLOCK_ZONE(zone); |
| 15916 | } |
| 15917 | |
| 15918 | void |
| 15919 | dns_zone_setsigvalidityinterval(dns_zone_t *zone, uint32_t interval) { |
| 15920 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15921 | |
| 15922 | zone->sigvalidityinterval = interval; |
| 15923 | } |
| 15924 | |
| 15925 | uint32_t |
| 15926 | dns_zone_getsigvalidityinterval(dns_zone_t *zone) { |
| 15927 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15928 | |
| 15929 | return (zone->sigvalidityinterval); |
| 15930 | } |
| 15931 | |
| 15932 | void |
| 15933 | dns_zone_setkeyvalidityinterval(dns_zone_t *zone, uint32_t interval) { |
| 15934 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15935 | |
| 15936 | zone->keyvalidityinterval = interval; |
| 15937 | } |
| 15938 | |
| 15939 | uint32_t |
| 15940 | dns_zone_getkeyvalidityinterval(dns_zone_t *zone) { |
| 15941 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15942 | |
| 15943 | return (zone->keyvalidityinterval); |
| 15944 | } |
| 15945 | |
| 15946 | void |
| 15947 | dns_zone_setsigresigninginterval(dns_zone_t *zone, uint32_t interval) { |
| 15948 | isc_time_t now; |
| 15949 | |
| 15950 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15951 | |
| 15952 | LOCK_ZONE(zone); |
| 15953 | zone->sigresigninginterval = interval; |
| 15954 | set_resigntime(zone); |
| 15955 | if (zone->task != NULL) { |
| 15956 | TIME_NOW(&now); |
| 15957 | zone_settimer(zone, &now); |
| 15958 | } |
| 15959 | UNLOCK_ZONE(zone); |
| 15960 | } |
| 15961 | |
| 15962 | uint32_t |
| 15963 | dns_zone_getsigresigninginterval(dns_zone_t *zone) { |
| 15964 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 15965 | |
| 15966 | return (zone->sigresigninginterval); |
| 15967 | } |
| 15968 | |
| 15969 | static void |
| 15970 | queue_xfrin(dns_zone_t *zone) { |
| 15971 | const char me[] = "queue_xfrin" ; |
| 15972 | isc_result_t result; |
| 15973 | dns_zonemgr_t *zmgr = zone->zmgr; |
| 15974 | |
| 15975 | ENTER; |
| 15976 | |
| 15977 | INSIST(zone->statelist == NULL); |
| 15978 | |
| 15979 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 15980 | ISC_LIST_APPEND(zmgr->waiting_for_xfrin, zone, statelink); |
| 15981 | LOCK_ZONE(zone); |
| 15982 | zone->irefs++; |
| 15983 | UNLOCK_ZONE(zone); |
| 15984 | zone->statelist = &zmgr->waiting_for_xfrin; |
| 15985 | result = zmgr_start_xfrin_ifquota(zmgr, zone); |
| 15986 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 15987 | |
| 15988 | if (result == ISC_R_QUOTA) { |
| 15989 | dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, |
| 15990 | "zone transfer deferred due to quota" ); |
| 15991 | } else if (result != ISC_R_SUCCESS) { |
| 15992 | dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_ERROR, |
| 15993 | "starting zone transfer: %s" , |
| 15994 | isc_result_totext(result)); |
| 15995 | } |
| 15996 | } |
| 15997 | |
| 15998 | /* |
| 15999 | * This event callback is called when a zone has received |
| 16000 | * any necessary zone transfer quota. This is the time |
| 16001 | * to go ahead and start the transfer. |
| 16002 | */ |
| 16003 | static void |
| 16004 | got_transfer_quota(isc_task_t *task, isc_event_t *event) { |
| 16005 | isc_result_t result = ISC_R_SUCCESS; |
| 16006 | dns_peer_t *peer = NULL; |
| 16007 | char master[ISC_SOCKADDR_FORMATSIZE]; |
| 16008 | char source[ISC_SOCKADDR_FORMATSIZE]; |
| 16009 | dns_rdatatype_t xfrtype; |
| 16010 | dns_zone_t *zone = event->ev_arg; |
| 16011 | isc_netaddr_t masterip; |
| 16012 | isc_sockaddr_t sourceaddr; |
| 16013 | isc_sockaddr_t masteraddr; |
| 16014 | isc_time_t now; |
| 16015 | const char *soa_before = "" ; |
| 16016 | isc_dscp_t dscp = -1; |
| 16017 | bool loaded; |
| 16018 | |
| 16019 | UNUSED(task); |
| 16020 | |
| 16021 | INSIST(task == zone->task); |
| 16022 | |
| 16023 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { |
| 16024 | result = ISC_R_CANCELED; |
| 16025 | goto cleanup; |
| 16026 | } |
| 16027 | |
| 16028 | TIME_NOW(&now); |
| 16029 | |
| 16030 | isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); |
| 16031 | if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, |
| 16032 | &zone->sourceaddr, &now)) |
| 16033 | { |
| 16034 | isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); |
| 16035 | dns_zone_log(zone, ISC_LOG_INFO, |
| 16036 | "got_transfer_quota: skipping zone transfer as " |
| 16037 | "master %s (source %s) is unreachable (cached)" , |
| 16038 | master, source); |
| 16039 | result = ISC_R_CANCELED; |
| 16040 | goto cleanup; |
| 16041 | } |
| 16042 | |
| 16043 | isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); |
| 16044 | (void)dns_peerlist_peerbyaddr(zone->view->peers, &masterip, &peer); |
| 16045 | |
| 16046 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) |
| 16047 | soa_before = "SOA before " ; |
| 16048 | /* |
| 16049 | * Decide whether we should request IXFR or AXFR. |
| 16050 | */ |
| 16051 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 16052 | loaded = (zone->db != NULL); |
| 16053 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 16054 | |
| 16055 | if (!loaded) { |
| 16056 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 16057 | "no database exists yet, requesting AXFR of " |
| 16058 | "initial version from %s" , master); |
| 16059 | xfrtype = dns_rdatatype_axfr; |
| 16060 | } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { |
| 16061 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 16062 | "forced reload, requesting AXFR of " |
| 16063 | "initial version from %s" , master); |
| 16064 | xfrtype = dns_rdatatype_axfr; |
| 16065 | } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLAG_NOIXFR)) { |
| 16066 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 16067 | "retrying with AXFR from %s due to " |
| 16068 | "previous IXFR failure" , master); |
| 16069 | xfrtype = dns_rdatatype_axfr; |
| 16070 | LOCK_ZONE(zone); |
| 16071 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLAG_NOIXFR); |
| 16072 | UNLOCK_ZONE(zone); |
| 16073 | } else { |
| 16074 | bool use_ixfr = true; |
| 16075 | if (peer != NULL) |
| 16076 | result = dns_peer_getrequestixfr(peer, &use_ixfr); |
| 16077 | if (peer == NULL || result != ISC_R_SUCCESS) |
| 16078 | use_ixfr = zone->requestixfr; |
| 16079 | if (use_ixfr == false) { |
| 16080 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 16081 | "IXFR disabled, requesting %sAXFR from %s" , |
| 16082 | soa_before, master); |
| 16083 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) |
| 16084 | xfrtype = dns_rdatatype_soa; |
| 16085 | else |
| 16086 | xfrtype = dns_rdatatype_axfr; |
| 16087 | } else { |
| 16088 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 16089 | "requesting IXFR from %s" , master); |
| 16090 | xfrtype = dns_rdatatype_ixfr; |
| 16091 | } |
| 16092 | } |
| 16093 | |
| 16094 | /* |
| 16095 | * Determine if we should attempt to sign the request with TSIG. |
| 16096 | */ |
| 16097 | result = ISC_R_NOTFOUND; |
| 16098 | |
| 16099 | /* |
| 16100 | * First, look for a tsig key in the master statement, then |
| 16101 | * try for a server key. |
| 16102 | */ |
| 16103 | if ((zone->masterkeynames != NULL) && |
| 16104 | (zone->masterkeynames[zone->curmaster] != NULL)) { |
| 16105 | dns_view_t *view = dns_zone_getview(zone); |
| 16106 | dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; |
| 16107 | result = dns_view_gettsig(view, keyname, &zone->tsigkey); |
| 16108 | } |
| 16109 | if (zone->tsigkey == NULL) |
| 16110 | result = dns_view_getpeertsig(zone->view, &masterip, |
| 16111 | &zone->tsigkey); |
| 16112 | |
| 16113 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { |
| 16114 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 16115 | "could not get TSIG key for zone transfer: %s" , |
| 16116 | isc_result_totext(result)); |
| 16117 | } |
| 16118 | |
| 16119 | if (zone->masterdscps != NULL) |
| 16120 | dscp = zone->masterdscps[zone->curmaster]; |
| 16121 | |
| 16122 | LOCK_ZONE(zone); |
| 16123 | masteraddr = zone->masteraddr; |
| 16124 | sourceaddr = zone->sourceaddr; |
| 16125 | switch (isc_sockaddr_pf(&masteraddr)) { |
| 16126 | case PF_INET: |
| 16127 | if (dscp == -1) |
| 16128 | dscp = zone->xfrsource4dscp; |
| 16129 | break; |
| 16130 | case PF_INET6: |
| 16131 | if (dscp == -1) |
| 16132 | dscp = zone->xfrsource6dscp; |
| 16133 | break; |
| 16134 | default: |
| 16135 | INSIST(0); |
| 16136 | ISC_UNREACHABLE(); |
| 16137 | } |
| 16138 | UNLOCK_ZONE(zone); |
| 16139 | INSIST(isc_sockaddr_pf(&masteraddr) == isc_sockaddr_pf(&sourceaddr)); |
| 16140 | result = dns_xfrin_create(zone, xfrtype, &masteraddr, &sourceaddr, |
| 16141 | dscp, zone->tsigkey, zone->mctx, |
| 16142 | zone->zmgr->timermgr, zone->zmgr->socketmgr, |
| 16143 | zone->task, zone_xfrdone, &zone->xfr); |
| 16144 | if (result == ISC_R_SUCCESS) { |
| 16145 | LOCK_ZONE(zone); |
| 16146 | if (xfrtype == dns_rdatatype_axfr) { |
| 16147 | if (isc_sockaddr_pf(&masteraddr) == PF_INET) |
| 16148 | inc_stats(zone, dns_zonestatscounter_axfrreqv4); |
| 16149 | else |
| 16150 | inc_stats(zone, dns_zonestatscounter_axfrreqv6); |
| 16151 | } else if (xfrtype == dns_rdatatype_ixfr) { |
| 16152 | if (isc_sockaddr_pf(&masteraddr) == PF_INET) |
| 16153 | inc_stats(zone, dns_zonestatscounter_ixfrreqv4); |
| 16154 | else |
| 16155 | inc_stats(zone, dns_zonestatscounter_ixfrreqv6); |
| 16156 | } |
| 16157 | UNLOCK_ZONE(zone); |
| 16158 | } |
| 16159 | cleanup: |
| 16160 | /* |
| 16161 | * Any failure in this function is handled like a failed |
| 16162 | * zone transfer. This ensures that we get removed from |
| 16163 | * zmgr->xfrin_in_progress. |
| 16164 | */ |
| 16165 | if (result != ISC_R_SUCCESS) |
| 16166 | zone_xfrdone(zone, result); |
| 16167 | |
| 16168 | isc_event_free(&event); |
| 16169 | } |
| 16170 | |
| 16171 | /* |
| 16172 | * Update forwarding support. |
| 16173 | */ |
| 16174 | |
| 16175 | static void |
| 16176 | forward_destroy(dns_forward_t *forward) { |
| 16177 | |
| 16178 | forward->magic = 0; |
| 16179 | if (forward->request != NULL) |
| 16180 | dns_request_destroy(&forward->request); |
| 16181 | if (forward->msgbuf != NULL) |
| 16182 | isc_buffer_free(&forward->msgbuf); |
| 16183 | if (forward->zone != NULL) { |
| 16184 | LOCK(&forward->zone->lock); |
| 16185 | if (ISC_LINK_LINKED(forward, link)) |
| 16186 | ISC_LIST_UNLINK(forward->zone->forwards, forward, link); |
| 16187 | UNLOCK(&forward->zone->lock); |
| 16188 | dns_zone_idetach(&forward->zone); |
| 16189 | } |
| 16190 | isc_mem_putanddetach(&forward->mctx, forward, sizeof(*forward)); |
| 16191 | } |
| 16192 | |
| 16193 | static isc_result_t |
| 16194 | sendtomaster(dns_forward_t *forward) { |
| 16195 | isc_result_t result; |
| 16196 | isc_sockaddr_t src; |
| 16197 | isc_dscp_t dscp = -1; |
| 16198 | |
| 16199 | LOCK_ZONE(forward->zone); |
| 16200 | |
| 16201 | if (DNS_ZONE_FLAG(forward->zone, DNS_ZONEFLG_EXITING)) { |
| 16202 | UNLOCK_ZONE(forward->zone); |
| 16203 | return (ISC_R_CANCELED); |
| 16204 | } |
| 16205 | |
| 16206 | if (forward->which >= forward->zone->masterscnt) { |
| 16207 | UNLOCK_ZONE(forward->zone); |
| 16208 | return (ISC_R_NOMORE); |
| 16209 | } |
| 16210 | |
| 16211 | forward->addr = forward->zone->masters[forward->which]; |
| 16212 | /* |
| 16213 | * Always use TCP regardless of whether the original update |
| 16214 | * used TCP. |
| 16215 | * XXX The timeout may but a bit small if we are far down a |
| 16216 | * transfer graph and the master has to try several masters. |
| 16217 | */ |
| 16218 | switch (isc_sockaddr_pf(&forward->addr)) { |
| 16219 | case PF_INET: |
| 16220 | src = forward->zone->xfrsource4; |
| 16221 | dscp = forward->zone->xfrsource4dscp; |
| 16222 | break; |
| 16223 | case PF_INET6: |
| 16224 | src = forward->zone->xfrsource6; |
| 16225 | dscp = forward->zone->xfrsource6dscp; |
| 16226 | break; |
| 16227 | default: |
| 16228 | result = ISC_R_NOTIMPLEMENTED; |
| 16229 | goto unlock; |
| 16230 | } |
| 16231 | result = dns_request_createraw(forward->zone->view->requestmgr, |
| 16232 | forward->msgbuf, |
| 16233 | &src, &forward->addr, dscp, |
| 16234 | forward->options, 15 /* XXX */, |
| 16235 | 0, 0, forward->zone->task, |
| 16236 | forward_callback, forward, |
| 16237 | &forward->request); |
| 16238 | if (result == ISC_R_SUCCESS) { |
| 16239 | if (!ISC_LINK_LINKED(forward, link)) |
| 16240 | ISC_LIST_APPEND(forward->zone->forwards, forward, link); |
| 16241 | } |
| 16242 | |
| 16243 | unlock: |
| 16244 | UNLOCK_ZONE(forward->zone); |
| 16245 | return (result); |
| 16246 | } |
| 16247 | |
| 16248 | static void |
| 16249 | forward_callback(isc_task_t *task, isc_event_t *event) { |
| 16250 | const char me[] = "forward_callback" ; |
| 16251 | dns_requestevent_t *revent = (dns_requestevent_t *)event; |
| 16252 | dns_message_t *msg = NULL; |
| 16253 | char master[ISC_SOCKADDR_FORMATSIZE]; |
| 16254 | isc_result_t result; |
| 16255 | dns_forward_t *forward; |
| 16256 | dns_zone_t *zone; |
| 16257 | |
| 16258 | UNUSED(task); |
| 16259 | |
| 16260 | forward = revent->ev_arg; |
| 16261 | INSIST(DNS_FORWARD_VALID(forward)); |
| 16262 | zone = forward->zone; |
| 16263 | INSIST(DNS_ZONE_VALID(zone)); |
| 16264 | |
| 16265 | ENTER; |
| 16266 | |
| 16267 | isc_sockaddr_format(&forward->addr, master, sizeof(master)); |
| 16268 | |
| 16269 | if (revent->result != ISC_R_SUCCESS) { |
| 16270 | dns_zone_log(zone, ISC_LOG_INFO, |
| 16271 | "could not forward dynamic update to %s: %s" , |
| 16272 | master, dns_result_totext(revent->result)); |
| 16273 | goto next_master; |
| 16274 | } |
| 16275 | |
| 16276 | result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); |
| 16277 | if (result != ISC_R_SUCCESS) |
| 16278 | goto next_master; |
| 16279 | |
| 16280 | result = dns_request_getresponse(revent->request, msg, |
| 16281 | DNS_MESSAGEPARSE_PRESERVEORDER | |
| 16282 | DNS_MESSAGEPARSE_CLONEBUFFER); |
| 16283 | if (result != ISC_R_SUCCESS) |
| 16284 | goto next_master; |
| 16285 | |
| 16286 | switch (msg->rcode) { |
| 16287 | /* |
| 16288 | * Pass these rcodes back to client. |
| 16289 | */ |
| 16290 | case dns_rcode_noerror: |
| 16291 | case dns_rcode_yxdomain: |
| 16292 | case dns_rcode_yxrrset: |
| 16293 | case dns_rcode_nxrrset: |
| 16294 | case dns_rcode_refused: |
| 16295 | case dns_rcode_nxdomain: { |
| 16296 | char rcode[128]; |
| 16297 | isc_buffer_t rb; |
| 16298 | |
| 16299 | isc_buffer_init(&rb, rcode, sizeof(rcode)); |
| 16300 | (void)dns_rcode_totext(msg->rcode, &rb); |
| 16301 | dns_zone_log(zone, ISC_LOG_INFO, |
| 16302 | "forwarded dynamic update: " |
| 16303 | "master %s returned: %.*s" , |
| 16304 | master, (int)rb.used, rcode); |
| 16305 | break; |
| 16306 | } |
| 16307 | |
| 16308 | /* These should not occur if the masters/zone are valid. */ |
| 16309 | case dns_rcode_notzone: |
| 16310 | case dns_rcode_notauth: { |
| 16311 | char rcode[128]; |
| 16312 | isc_buffer_t rb; |
| 16313 | |
| 16314 | isc_buffer_init(&rb, rcode, sizeof(rcode)); |
| 16315 | (void)dns_rcode_totext(msg->rcode, &rb); |
| 16316 | dns_zone_log(zone, ISC_LOG_WARNING, |
| 16317 | "forwarding dynamic update: " |
| 16318 | "unexpected response: master %s returned: %.*s" , |
| 16319 | master, (int)rb.used, rcode); |
| 16320 | goto next_master; |
| 16321 | } |
| 16322 | |
| 16323 | /* Try another server for these rcodes. */ |
| 16324 | case dns_rcode_formerr: |
| 16325 | case dns_rcode_servfail: |
| 16326 | case dns_rcode_notimp: |
| 16327 | case dns_rcode_badvers: |
| 16328 | default: |
| 16329 | goto next_master; |
| 16330 | } |
| 16331 | |
| 16332 | /* call callback */ |
| 16333 | (forward->callback)(forward->callback_arg, ISC_R_SUCCESS, msg); |
| 16334 | msg = NULL; |
| 16335 | dns_request_destroy(&forward->request); |
| 16336 | forward_destroy(forward); |
| 16337 | isc_event_free(&event); |
| 16338 | return; |
| 16339 | |
| 16340 | next_master: |
| 16341 | if (msg != NULL) |
| 16342 | dns_message_destroy(&msg); |
| 16343 | isc_event_free(&event); |
| 16344 | forward->which++; |
| 16345 | dns_request_destroy(&forward->request); |
| 16346 | result = sendtomaster(forward); |
| 16347 | if (result != ISC_R_SUCCESS) { |
| 16348 | /* call callback */ |
| 16349 | dns_zone_log(zone, ISC_LOG_DEBUG(3), |
| 16350 | "exhausted dynamic update forwarder list" ); |
| 16351 | (forward->callback)(forward->callback_arg, result, NULL); |
| 16352 | forward_destroy(forward); |
| 16353 | } |
| 16354 | } |
| 16355 | |
| 16356 | isc_result_t |
| 16357 | dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg, |
| 16358 | dns_updatecallback_t callback, void *callback_arg) |
| 16359 | { |
| 16360 | dns_forward_t *forward; |
| 16361 | isc_result_t result; |
| 16362 | isc_region_t *mr; |
| 16363 | |
| 16364 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 16365 | REQUIRE(msg != NULL); |
| 16366 | REQUIRE(callback != NULL); |
| 16367 | |
| 16368 | forward = isc_mem_get(zone->mctx, sizeof(*forward)); |
| 16369 | if (forward == NULL) |
| 16370 | return (ISC_R_NOMEMORY); |
| 16371 | |
| 16372 | forward->request = NULL; |
| 16373 | forward->zone = NULL; |
| 16374 | forward->msgbuf = NULL; |
| 16375 | forward->which = 0; |
| 16376 | forward->mctx = 0; |
| 16377 | forward->callback = callback; |
| 16378 | forward->callback_arg = callback_arg; |
| 16379 | ISC_LINK_INIT(forward, link); |
| 16380 | forward->magic = FORWARD_MAGIC; |
| 16381 | forward->options = DNS_REQUESTOPT_TCP; |
| 16382 | /* |
| 16383 | * If we have a SIG(0) signed message we need to preserve the |
| 16384 | * query id as that is included in the SIG(0) computation. |
| 16385 | */ |
| 16386 | if (msg->sig0 != NULL) |
| 16387 | forward->options |= DNS_REQUESTOPT_FIXEDID; |
| 16388 | |
| 16389 | mr = dns_message_getrawmessage(msg); |
| 16390 | if (mr == NULL) { |
| 16391 | result = ISC_R_UNEXPECTEDEND; |
| 16392 | goto cleanup; |
| 16393 | } |
| 16394 | |
| 16395 | result = isc_buffer_allocate(zone->mctx, &forward->msgbuf, mr->length); |
| 16396 | if (result != ISC_R_SUCCESS) |
| 16397 | goto cleanup; |
| 16398 | result = isc_buffer_copyregion(forward->msgbuf, mr); |
| 16399 | if (result != ISC_R_SUCCESS) |
| 16400 | goto cleanup; |
| 16401 | |
| 16402 | isc_mem_attach(zone->mctx, &forward->mctx); |
| 16403 | dns_zone_iattach(zone, &forward->zone); |
| 16404 | result = sendtomaster(forward); |
| 16405 | |
| 16406 | cleanup: |
| 16407 | if (result != ISC_R_SUCCESS) { |
| 16408 | forward_destroy(forward); |
| 16409 | } |
| 16410 | return (result); |
| 16411 | } |
| 16412 | |
| 16413 | isc_result_t |
| 16414 | dns_zone_next(dns_zone_t *zone, dns_zone_t **next) { |
| 16415 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 16416 | REQUIRE(next != NULL && *next == NULL); |
| 16417 | |
| 16418 | *next = ISC_LIST_NEXT(zone, link); |
| 16419 | if (*next == NULL) |
| 16420 | return (ISC_R_NOMORE); |
| 16421 | else |
| 16422 | return (ISC_R_SUCCESS); |
| 16423 | } |
| 16424 | |
| 16425 | isc_result_t |
| 16426 | dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first) { |
| 16427 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16428 | REQUIRE(first != NULL && *first == NULL); |
| 16429 | |
| 16430 | *first = ISC_LIST_HEAD(zmgr->zones); |
| 16431 | if (*first == NULL) |
| 16432 | return (ISC_R_NOMORE); |
| 16433 | else |
| 16434 | return (ISC_R_SUCCESS); |
| 16435 | } |
| 16436 | |
| 16437 | /*** |
| 16438 | *** Zone manager. |
| 16439 | ***/ |
| 16440 | |
| 16441 | isc_result_t |
| 16442 | dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, |
| 16443 | isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, |
| 16444 | dns_zonemgr_t **zmgrp) |
| 16445 | { |
| 16446 | dns_zonemgr_t *zmgr; |
| 16447 | isc_result_t result; |
| 16448 | |
| 16449 | zmgr = isc_mem_get(mctx, sizeof(*zmgr)); |
| 16450 | if (zmgr == NULL) |
| 16451 | return (ISC_R_NOMEMORY); |
| 16452 | zmgr->mctx = NULL; |
| 16453 | zmgr->refs = 1; |
| 16454 | isc_mem_attach(mctx, &zmgr->mctx); |
| 16455 | zmgr->taskmgr = taskmgr; |
| 16456 | zmgr->timermgr = timermgr; |
| 16457 | zmgr->socketmgr = socketmgr; |
| 16458 | zmgr->zonetasks = NULL; |
| 16459 | zmgr->loadtasks = NULL; |
| 16460 | zmgr->mctxpool = NULL; |
| 16461 | zmgr->task = NULL; |
| 16462 | zmgr->notifyrl = NULL; |
| 16463 | zmgr->refreshrl = NULL; |
| 16464 | zmgr->startupnotifyrl = NULL; |
| 16465 | zmgr->startuprefreshrl = NULL; |
| 16466 | ISC_LIST_INIT(zmgr->zones); |
| 16467 | ISC_LIST_INIT(zmgr->waiting_for_xfrin); |
| 16468 | ISC_LIST_INIT(zmgr->xfrin_in_progress); |
| 16469 | memset(zmgr->unreachable, 0, sizeof(zmgr->unreachable)); |
| 16470 | result = isc_rwlock_init(&zmgr->rwlock, 0, 0); |
| 16471 | if (result != ISC_R_SUCCESS) |
| 16472 | goto free_mem; |
| 16473 | |
| 16474 | zmgr->transfersin = 10; |
| 16475 | zmgr->transfersperns = 2; |
| 16476 | |
| 16477 | /* Unreachable lock. */ |
| 16478 | result = isc_rwlock_init(&zmgr->urlock, 0, 0); |
| 16479 | if (result != ISC_R_SUCCESS) |
| 16480 | goto free_rwlock; |
| 16481 | |
| 16482 | /* Create a single task for queueing of SOA queries. */ |
| 16483 | result = isc_task_create(taskmgr, 1, &zmgr->task); |
| 16484 | if (result != ISC_R_SUCCESS) |
| 16485 | goto free_urlock; |
| 16486 | |
| 16487 | isc_task_setname(zmgr->task, "zmgr" , zmgr); |
| 16488 | result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, |
| 16489 | &zmgr->notifyrl); |
| 16490 | if (result != ISC_R_SUCCESS) |
| 16491 | goto free_task; |
| 16492 | |
| 16493 | result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, |
| 16494 | &zmgr->refreshrl); |
| 16495 | if (result != ISC_R_SUCCESS) |
| 16496 | goto free_notifyrl; |
| 16497 | |
| 16498 | result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, |
| 16499 | &zmgr->startupnotifyrl); |
| 16500 | if (result != ISC_R_SUCCESS) |
| 16501 | goto free_refreshrl; |
| 16502 | |
| 16503 | result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, |
| 16504 | &zmgr->startuprefreshrl); |
| 16505 | if (result != ISC_R_SUCCESS) |
| 16506 | goto free_startupnotifyrl; |
| 16507 | |
| 16508 | /* default to 20 refresh queries / notifies per second. */ |
| 16509 | setrl(zmgr->notifyrl, &zmgr->notifyrate, 20); |
| 16510 | setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, 20); |
| 16511 | setrl(zmgr->refreshrl, &zmgr->serialqueryrate, 20); |
| 16512 | setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, 20); |
| 16513 | isc_ratelimiter_setpushpop(zmgr->startupnotifyrl, true); |
| 16514 | isc_ratelimiter_setpushpop(zmgr->startuprefreshrl, true); |
| 16515 | |
| 16516 | zmgr->iolimit = 1; |
| 16517 | zmgr->ioactive = 0; |
| 16518 | ISC_LIST_INIT(zmgr->high); |
| 16519 | ISC_LIST_INIT(zmgr->low); |
| 16520 | |
| 16521 | isc_mutex_init(&zmgr->iolock); |
| 16522 | |
| 16523 | zmgr->magic = ZONEMGR_MAGIC; |
| 16524 | |
| 16525 | *zmgrp = zmgr; |
| 16526 | return (ISC_R_SUCCESS); |
| 16527 | |
| 16528 | #if 0 |
| 16529 | free_iolock: |
| 16530 | isc_mutex_destroy(&zmgr->iolock); |
| 16531 | #endif |
| 16532 | free_startupnotifyrl: |
| 16533 | isc_ratelimiter_detach(&zmgr->startupnotifyrl); |
| 16534 | free_refreshrl: |
| 16535 | isc_ratelimiter_detach(&zmgr->refreshrl); |
| 16536 | free_notifyrl: |
| 16537 | isc_ratelimiter_detach(&zmgr->notifyrl); |
| 16538 | free_task: |
| 16539 | isc_task_detach(&zmgr->task); |
| 16540 | free_urlock: |
| 16541 | isc_rwlock_destroy(&zmgr->urlock); |
| 16542 | free_rwlock: |
| 16543 | isc_rwlock_destroy(&zmgr->rwlock); |
| 16544 | free_mem: |
| 16545 | isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr)); |
| 16546 | isc_mem_detach(&mctx); |
| 16547 | return (result); |
| 16548 | } |
| 16549 | |
| 16550 | isc_result_t |
| 16551 | dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) { |
| 16552 | isc_result_t result; |
| 16553 | isc_mem_t *mctx = NULL; |
| 16554 | dns_zone_t *zone = NULL; |
| 16555 | void *item; |
| 16556 | |
| 16557 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16558 | REQUIRE(zonep != NULL && *zonep == NULL); |
| 16559 | |
| 16560 | if (zmgr->mctxpool == NULL) |
| 16561 | return (ISC_R_FAILURE); |
| 16562 | |
| 16563 | item = isc_pool_get(zmgr->mctxpool); |
| 16564 | if (item == NULL) |
| 16565 | return (ISC_R_FAILURE); |
| 16566 | |
| 16567 | isc_mem_attach((isc_mem_t *) item, &mctx); |
| 16568 | result = dns_zone_create(&zone, mctx); |
| 16569 | isc_mem_detach(&mctx); |
| 16570 | |
| 16571 | if (result == ISC_R_SUCCESS) |
| 16572 | *zonep = zone; |
| 16573 | |
| 16574 | return (result); |
| 16575 | } |
| 16576 | |
| 16577 | isc_result_t |
| 16578 | dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { |
| 16579 | isc_result_t result; |
| 16580 | |
| 16581 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 16582 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16583 | |
| 16584 | if (zmgr->zonetasks == NULL) |
| 16585 | return (ISC_R_FAILURE); |
| 16586 | |
| 16587 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16588 | LOCK_ZONE(zone); |
| 16589 | REQUIRE(zone->task == NULL); |
| 16590 | REQUIRE(zone->timer == NULL); |
| 16591 | REQUIRE(zone->zmgr == NULL); |
| 16592 | |
| 16593 | isc_taskpool_gettask(zmgr->zonetasks, &zone->task); |
| 16594 | isc_taskpool_gettask(zmgr->loadtasks, &zone->loadtask); |
| 16595 | |
| 16596 | /* |
| 16597 | * Set the task name. The tag will arbitrarily point to one |
| 16598 | * of the zones sharing the task (in practice, the one |
| 16599 | * to be managed last). |
| 16600 | */ |
| 16601 | isc_task_setname(zone->task, "zone" , zone); |
| 16602 | isc_task_setname(zone->loadtask, "loadzone" , zone); |
| 16603 | |
| 16604 | result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive, |
| 16605 | NULL, NULL, |
| 16606 | zone->task, zone_timer, zone, |
| 16607 | &zone->timer); |
| 16608 | |
| 16609 | if (result != ISC_R_SUCCESS) |
| 16610 | goto cleanup_tasks; |
| 16611 | |
| 16612 | /* |
| 16613 | * The timer "holds" a iref. |
| 16614 | */ |
| 16615 | zone->irefs++; |
| 16616 | INSIST(zone->irefs != 0); |
| 16617 | |
| 16618 | ISC_LIST_APPEND(zmgr->zones, zone, link); |
| 16619 | zone->zmgr = zmgr; |
| 16620 | zmgr->refs++; |
| 16621 | |
| 16622 | goto unlock; |
| 16623 | |
| 16624 | cleanup_tasks: |
| 16625 | isc_task_detach(&zone->loadtask); |
| 16626 | isc_task_detach(&zone->task); |
| 16627 | |
| 16628 | unlock: |
| 16629 | UNLOCK_ZONE(zone); |
| 16630 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16631 | return (result); |
| 16632 | } |
| 16633 | |
| 16634 | void |
| 16635 | dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { |
| 16636 | bool free_now = false; |
| 16637 | |
| 16638 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 16639 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16640 | REQUIRE(zone->zmgr == zmgr); |
| 16641 | |
| 16642 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16643 | LOCK_ZONE(zone); |
| 16644 | |
| 16645 | ISC_LIST_UNLINK(zmgr->zones, zone, link); |
| 16646 | zone->zmgr = NULL; |
| 16647 | zmgr->refs--; |
| 16648 | if (zmgr->refs == 0) |
| 16649 | free_now = true; |
| 16650 | |
| 16651 | UNLOCK_ZONE(zone); |
| 16652 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16653 | |
| 16654 | if (free_now) |
| 16655 | zonemgr_free(zmgr); |
| 16656 | ENSURE(zone->zmgr == NULL); |
| 16657 | } |
| 16658 | |
| 16659 | void |
| 16660 | dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target) { |
| 16661 | REQUIRE(DNS_ZONEMGR_VALID(source)); |
| 16662 | REQUIRE(target != NULL && *target == NULL); |
| 16663 | |
| 16664 | RWLOCK(&source->rwlock, isc_rwlocktype_write); |
| 16665 | REQUIRE(source->refs > 0); |
| 16666 | source->refs++; |
| 16667 | INSIST(source->refs > 0); |
| 16668 | RWUNLOCK(&source->rwlock, isc_rwlocktype_write); |
| 16669 | *target = source; |
| 16670 | } |
| 16671 | |
| 16672 | void |
| 16673 | dns_zonemgr_detach(dns_zonemgr_t **zmgrp) { |
| 16674 | dns_zonemgr_t *zmgr; |
| 16675 | bool free_now = false; |
| 16676 | |
| 16677 | REQUIRE(zmgrp != NULL); |
| 16678 | zmgr = *zmgrp; |
| 16679 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16680 | |
| 16681 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16682 | zmgr->refs--; |
| 16683 | if (zmgr->refs == 0) |
| 16684 | free_now = true; |
| 16685 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16686 | |
| 16687 | if (free_now) |
| 16688 | zonemgr_free(zmgr); |
| 16689 | *zmgrp = NULL; |
| 16690 | } |
| 16691 | |
| 16692 | isc_result_t |
| 16693 | dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) { |
| 16694 | dns_zone_t *p; |
| 16695 | |
| 16696 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16697 | |
| 16698 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); |
| 16699 | for (p = ISC_LIST_HEAD(zmgr->zones); |
| 16700 | p != NULL; |
| 16701 | p = ISC_LIST_NEXT(p, link)) |
| 16702 | { |
| 16703 | dns_zone_maintenance(p); |
| 16704 | } |
| 16705 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); |
| 16706 | |
| 16707 | /* |
| 16708 | * Recent configuration changes may have increased the |
| 16709 | * amount of available transfers quota. Make sure any |
| 16710 | * transfers currently blocked on quota get started if |
| 16711 | * possible. |
| 16712 | */ |
| 16713 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16714 | zmgr_resume_xfrs(zmgr, true); |
| 16715 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16716 | return (ISC_R_SUCCESS); |
| 16717 | } |
| 16718 | |
| 16719 | void |
| 16720 | dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr) { |
| 16721 | |
| 16722 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16723 | |
| 16724 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16725 | zmgr_resume_xfrs(zmgr, true); |
| 16726 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 16727 | } |
| 16728 | |
| 16729 | void |
| 16730 | dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) { |
| 16731 | dns_zone_t *zone; |
| 16732 | |
| 16733 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16734 | |
| 16735 | isc_ratelimiter_shutdown(zmgr->notifyrl); |
| 16736 | isc_ratelimiter_shutdown(zmgr->refreshrl); |
| 16737 | isc_ratelimiter_shutdown(zmgr->startupnotifyrl); |
| 16738 | isc_ratelimiter_shutdown(zmgr->startuprefreshrl); |
| 16739 | |
| 16740 | if (zmgr->task != NULL) |
| 16741 | isc_task_destroy(&zmgr->task); |
| 16742 | if (zmgr->zonetasks != NULL) |
| 16743 | isc_taskpool_destroy(&zmgr->zonetasks); |
| 16744 | if (zmgr->loadtasks != NULL) |
| 16745 | isc_taskpool_destroy(&zmgr->loadtasks); |
| 16746 | if (zmgr->mctxpool != NULL) |
| 16747 | isc_pool_destroy(&zmgr->mctxpool); |
| 16748 | |
| 16749 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); |
| 16750 | for (zone = ISC_LIST_HEAD(zmgr->zones); |
| 16751 | zone != NULL; |
| 16752 | zone = ISC_LIST_NEXT(zone, link)) |
| 16753 | { |
| 16754 | LOCK_ZONE(zone); |
| 16755 | forward_cancel(zone); |
| 16756 | UNLOCK_ZONE(zone); |
| 16757 | } |
| 16758 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); |
| 16759 | } |
| 16760 | |
| 16761 | static isc_result_t |
| 16762 | mctxinit(void **target, void *arg) { |
| 16763 | isc_result_t result; |
| 16764 | isc_mem_t *mctx = NULL; |
| 16765 | |
| 16766 | UNUSED(arg); |
| 16767 | |
| 16768 | REQUIRE(target != NULL && *target == NULL); |
| 16769 | |
| 16770 | result = isc_mem_create(0, 0, &mctx); |
| 16771 | if (result != ISC_R_SUCCESS) |
| 16772 | return (result); |
| 16773 | isc_mem_setname(mctx, "zonemgr-pool" , NULL); |
| 16774 | |
| 16775 | *target = mctx; |
| 16776 | return (ISC_R_SUCCESS); |
| 16777 | } |
| 16778 | |
| 16779 | static void |
| 16780 | mctxfree(void **target) { |
| 16781 | isc_mem_t *mctx = *(isc_mem_t **) target; |
| 16782 | isc_mem_detach(&mctx); |
| 16783 | *target = NULL; |
| 16784 | } |
| 16785 | |
| 16786 | #define ZONES_PER_TASK 100 |
| 16787 | #define ZONES_PER_MCTX 1000 |
| 16788 | |
| 16789 | isc_result_t |
| 16790 | dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) { |
| 16791 | isc_result_t result; |
| 16792 | int ntasks = num_zones / ZONES_PER_TASK; |
| 16793 | int nmctx = num_zones / ZONES_PER_MCTX; |
| 16794 | isc_taskpool_t *pool = NULL; |
| 16795 | isc_pool_t *mctxpool = NULL; |
| 16796 | |
| 16797 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16798 | |
| 16799 | /* |
| 16800 | * For anything fewer than 1000 zones we use 10 tasks in |
| 16801 | * the task pools. More than that, and we'll scale at one |
| 16802 | * task per 100 zones. Similarly, for anything smaller than |
| 16803 | * 2000 zones we use 2 memory contexts, then scale at 1:1000. |
| 16804 | */ |
| 16805 | if (ntasks < 10) |
| 16806 | ntasks = 10; |
| 16807 | if (nmctx < 2) |
| 16808 | nmctx = 2; |
| 16809 | |
| 16810 | /* Create or resize the zone task pools. */ |
| 16811 | if (zmgr->zonetasks == NULL) |
| 16812 | result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx, |
| 16813 | ntasks, 2, &pool); |
| 16814 | else |
| 16815 | result = isc_taskpool_expand(&zmgr->zonetasks, ntasks, &pool); |
| 16816 | |
| 16817 | if (result == ISC_R_SUCCESS) |
| 16818 | zmgr->zonetasks = pool; |
| 16819 | |
| 16820 | pool = NULL; |
| 16821 | if (zmgr->loadtasks == NULL) |
| 16822 | result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx, |
| 16823 | ntasks, 2, &pool); |
| 16824 | else |
| 16825 | result = isc_taskpool_expand(&zmgr->loadtasks, ntasks, &pool); |
| 16826 | |
| 16827 | if (result == ISC_R_SUCCESS) |
| 16828 | zmgr->loadtasks = pool; |
| 16829 | |
| 16830 | /* |
| 16831 | * We always set all tasks in the zone-load task pool to |
| 16832 | * privileged. This prevents other tasks in the system from |
| 16833 | * running while the server task manager is in privileged |
| 16834 | * mode. |
| 16835 | * |
| 16836 | * NOTE: If we start using task privileges for any other |
| 16837 | * part of the system than zone tasks, then this will need to be |
| 16838 | * revisted. In that case we'd want to turn on privileges for |
| 16839 | * zone tasks only when we were loading, and turn them off the |
| 16840 | * rest of the time. For now, however, it's okay to just |
| 16841 | * set it and forget it. |
| 16842 | */ |
| 16843 | isc_taskpool_setprivilege(zmgr->loadtasks, true); |
| 16844 | |
| 16845 | /* Create or resize the zone memory context pool. */ |
| 16846 | if (zmgr->mctxpool == NULL) |
| 16847 | result = isc_pool_create(zmgr->mctx, nmctx, mctxfree, |
| 16848 | mctxinit, NULL, &mctxpool); |
| 16849 | else |
| 16850 | result = isc_pool_expand(&zmgr->mctxpool, nmctx, &mctxpool); |
| 16851 | |
| 16852 | if (result == ISC_R_SUCCESS) |
| 16853 | zmgr->mctxpool = mctxpool; |
| 16854 | |
| 16855 | return (result); |
| 16856 | } |
| 16857 | |
| 16858 | static void |
| 16859 | zonemgr_free(dns_zonemgr_t *zmgr) { |
| 16860 | isc_mem_t *mctx; |
| 16861 | |
| 16862 | INSIST(zmgr->refs == 0); |
| 16863 | INSIST(ISC_LIST_EMPTY(zmgr->zones)); |
| 16864 | |
| 16865 | zmgr->magic = 0; |
| 16866 | |
| 16867 | isc_mutex_destroy(&zmgr->iolock); |
| 16868 | isc_ratelimiter_detach(&zmgr->notifyrl); |
| 16869 | isc_ratelimiter_detach(&zmgr->refreshrl); |
| 16870 | isc_ratelimiter_detach(&zmgr->startupnotifyrl); |
| 16871 | isc_ratelimiter_detach(&zmgr->startuprefreshrl); |
| 16872 | |
| 16873 | isc_rwlock_destroy(&zmgr->urlock); |
| 16874 | isc_rwlock_destroy(&zmgr->rwlock); |
| 16875 | mctx = zmgr->mctx; |
| 16876 | isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr)); |
| 16877 | isc_mem_detach(&mctx); |
| 16878 | } |
| 16879 | |
| 16880 | void |
| 16881 | dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value) { |
| 16882 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16883 | |
| 16884 | zmgr->transfersin = value; |
| 16885 | } |
| 16886 | |
| 16887 | uint32_t |
| 16888 | dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr) { |
| 16889 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16890 | |
| 16891 | return (zmgr->transfersin); |
| 16892 | } |
| 16893 | |
| 16894 | void |
| 16895 | dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value) { |
| 16896 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16897 | |
| 16898 | zmgr->transfersperns = value; |
| 16899 | } |
| 16900 | |
| 16901 | uint32_t |
| 16902 | dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr) { |
| 16903 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 16904 | |
| 16905 | return (zmgr->transfersperns); |
| 16906 | } |
| 16907 | |
| 16908 | /* |
| 16909 | * Try to start a new incoming zone transfer to fill a quota |
| 16910 | * slot that was just vacated. |
| 16911 | * |
| 16912 | * Requires: |
| 16913 | * The zone manager is locked by the caller. |
| 16914 | */ |
| 16915 | static void |
| 16916 | zmgr_resume_xfrs(dns_zonemgr_t *zmgr, bool multi) { |
| 16917 | dns_zone_t *zone; |
| 16918 | dns_zone_t *next; |
| 16919 | |
| 16920 | for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin); |
| 16921 | zone != NULL; |
| 16922 | zone = next) |
| 16923 | { |
| 16924 | isc_result_t result; |
| 16925 | next = ISC_LIST_NEXT(zone, statelink); |
| 16926 | result = zmgr_start_xfrin_ifquota(zmgr, zone); |
| 16927 | if (result == ISC_R_SUCCESS) { |
| 16928 | if (multi) |
| 16929 | continue; |
| 16930 | /* |
| 16931 | * We successfully filled the slot. We're done. |
| 16932 | */ |
| 16933 | break; |
| 16934 | } else if (result == ISC_R_QUOTA) { |
| 16935 | /* |
| 16936 | * Not enough quota. This is probably the per-server |
| 16937 | * quota, because we usually get called when a unit of |
| 16938 | * global quota has just been freed. Try the next |
| 16939 | * zone, it may succeed if it uses another master. |
| 16940 | */ |
| 16941 | continue; |
| 16942 | } else { |
| 16943 | dns_zone_log(zone, ISC_LOG_DEBUG(1), |
| 16944 | "starting zone transfer: %s" , |
| 16945 | isc_result_totext(result)); |
| 16946 | break; |
| 16947 | } |
| 16948 | } |
| 16949 | } |
| 16950 | |
| 16951 | /* |
| 16952 | * Try to start an incoming zone transfer for 'zone', quota permitting. |
| 16953 | * |
| 16954 | * Requires: |
| 16955 | * The zone manager is locked by the caller. |
| 16956 | * |
| 16957 | * Returns: |
| 16958 | * ISC_R_SUCCESS There was enough quota and we attempted to |
| 16959 | * start a transfer. zone_xfrdone() has been or will |
| 16960 | * be called. |
| 16961 | * ISC_R_QUOTA Not enough quota. |
| 16962 | * Others Failure. |
| 16963 | */ |
| 16964 | static isc_result_t |
| 16965 | zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { |
| 16966 | dns_peer_t *peer = NULL; |
| 16967 | isc_netaddr_t masterip; |
| 16968 | uint32_t nxfrsin, nxfrsperns; |
| 16969 | dns_zone_t *x; |
| 16970 | uint32_t maxtransfersin, maxtransfersperns; |
| 16971 | isc_event_t *e; |
| 16972 | |
| 16973 | /* |
| 16974 | * If we are exiting just pretend we got quota so the zone will |
| 16975 | * be cleaned up in the zone's task context. |
| 16976 | */ |
| 16977 | LOCK_ZONE(zone); |
| 16978 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { |
| 16979 | UNLOCK_ZONE(zone); |
| 16980 | goto gotquota; |
| 16981 | } |
| 16982 | |
| 16983 | /* |
| 16984 | * Find any configured information about the server we'd |
| 16985 | * like to transfer this zone from. |
| 16986 | */ |
| 16987 | isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); |
| 16988 | (void)dns_peerlist_peerbyaddr(zone->view->peers, &masterip, &peer); |
| 16989 | UNLOCK_ZONE(zone); |
| 16990 | |
| 16991 | /* |
| 16992 | * Determine the total maximum number of simultaneous |
| 16993 | * transfers allowed, and the maximum for this specific |
| 16994 | * master. |
| 16995 | */ |
| 16996 | maxtransfersin = zmgr->transfersin; |
| 16997 | maxtransfersperns = zmgr->transfersperns; |
| 16998 | if (peer != NULL) |
| 16999 | (void)dns_peer_gettransfers(peer, &maxtransfersperns); |
| 17000 | |
| 17001 | /* |
| 17002 | * Count the total number of transfers that are in progress, |
| 17003 | * and the number of transfers in progress from this master. |
| 17004 | * We linearly scan a list of all transfers; if this turns |
| 17005 | * out to be too slow, we could hash on the master address. |
| 17006 | */ |
| 17007 | nxfrsin = nxfrsperns = 0; |
| 17008 | for (x = ISC_LIST_HEAD(zmgr->xfrin_in_progress); |
| 17009 | x != NULL; |
| 17010 | x = ISC_LIST_NEXT(x, statelink)) |
| 17011 | { |
| 17012 | isc_netaddr_t xip; |
| 17013 | |
| 17014 | LOCK_ZONE(x); |
| 17015 | isc_netaddr_fromsockaddr(&xip, &x->masteraddr); |
| 17016 | UNLOCK_ZONE(x); |
| 17017 | |
| 17018 | nxfrsin++; |
| 17019 | if (isc_netaddr_equal(&xip, &masterip)) |
| 17020 | nxfrsperns++; |
| 17021 | } |
| 17022 | |
| 17023 | /* Enforce quota. */ |
| 17024 | if (nxfrsin >= maxtransfersin) |
| 17025 | return (ISC_R_QUOTA); |
| 17026 | |
| 17027 | if (nxfrsperns >= maxtransfersperns) |
| 17028 | return (ISC_R_QUOTA); |
| 17029 | |
| 17030 | gotquota: |
| 17031 | /* |
| 17032 | * We have sufficient quota. Move the zone to the "xfrin_in_progress" |
| 17033 | * list and send it an event to let it start the actual transfer in the |
| 17034 | * context of its own task. |
| 17035 | */ |
| 17036 | e = isc_event_allocate(zmgr->mctx, zmgr, DNS_EVENT_ZONESTARTXFRIN, |
| 17037 | got_transfer_quota, zone, sizeof(isc_event_t)); |
| 17038 | if (e == NULL) |
| 17039 | return (ISC_R_NOMEMORY); |
| 17040 | |
| 17041 | LOCK_ZONE(zone); |
| 17042 | INSIST(zone->statelist == &zmgr->waiting_for_xfrin); |
| 17043 | ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink); |
| 17044 | ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink); |
| 17045 | zone->statelist = &zmgr->xfrin_in_progress; |
| 17046 | isc_task_send(zone->task, &e); |
| 17047 | dns_zone_log(zone, ISC_LOG_INFO, "Transfer started." ); |
| 17048 | UNLOCK_ZONE(zone); |
| 17049 | |
| 17050 | return (ISC_R_SUCCESS); |
| 17051 | } |
| 17052 | |
| 17053 | void |
| 17054 | dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, uint32_t iolimit) { |
| 17055 | |
| 17056 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17057 | REQUIRE(iolimit > 0); |
| 17058 | |
| 17059 | zmgr->iolimit = iolimit; |
| 17060 | } |
| 17061 | |
| 17062 | uint32_t |
| 17063 | dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr) { |
| 17064 | |
| 17065 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17066 | |
| 17067 | return (zmgr->iolimit); |
| 17068 | } |
| 17069 | |
| 17070 | /* |
| 17071 | * Get permission to request a file handle from the OS. |
| 17072 | * An event will be sent to action when one is available. |
| 17073 | * There are two queues available (high and low), the high |
| 17074 | * queue will be serviced before the low one. |
| 17075 | * |
| 17076 | * zonemgr_putio() must be called after the event is delivered to |
| 17077 | * 'action'. |
| 17078 | */ |
| 17079 | |
| 17080 | static isc_result_t |
| 17081 | zonemgr_getio(dns_zonemgr_t *zmgr, bool high, |
| 17082 | isc_task_t *task, isc_taskaction_t action, void *arg, |
| 17083 | dns_io_t **iop) |
| 17084 | { |
| 17085 | dns_io_t *io; |
| 17086 | bool queue; |
| 17087 | |
| 17088 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17089 | REQUIRE(iop != NULL && *iop == NULL); |
| 17090 | |
| 17091 | io = isc_mem_get(zmgr->mctx, sizeof(*io)); |
| 17092 | if (io == NULL) |
| 17093 | return (ISC_R_NOMEMORY); |
| 17094 | |
| 17095 | io->event = isc_event_allocate(zmgr->mctx, task, DNS_EVENT_IOREADY, |
| 17096 | action, arg, sizeof(*io->event)); |
| 17097 | if (io->event == NULL) { |
| 17098 | isc_mem_put(zmgr->mctx, io, sizeof(*io)); |
| 17099 | return (ISC_R_NOMEMORY); |
| 17100 | } |
| 17101 | |
| 17102 | io->zmgr = zmgr; |
| 17103 | io->high = high; |
| 17104 | io->task = NULL; |
| 17105 | isc_task_attach(task, &io->task); |
| 17106 | ISC_LINK_INIT(io, link); |
| 17107 | io->magic = IO_MAGIC; |
| 17108 | |
| 17109 | LOCK(&zmgr->iolock); |
| 17110 | zmgr->ioactive++; |
| 17111 | queue = (zmgr->ioactive > zmgr->iolimit); |
| 17112 | if (queue) { |
| 17113 | if (io->high) |
| 17114 | ISC_LIST_APPEND(zmgr->high, io, link); |
| 17115 | else |
| 17116 | ISC_LIST_APPEND(zmgr->low, io, link); |
| 17117 | } |
| 17118 | UNLOCK(&zmgr->iolock); |
| 17119 | *iop = io; |
| 17120 | |
| 17121 | if (!queue) |
| 17122 | isc_task_send(io->task, &io->event); |
| 17123 | return (ISC_R_SUCCESS); |
| 17124 | } |
| 17125 | |
| 17126 | static void |
| 17127 | zonemgr_putio(dns_io_t **iop) { |
| 17128 | dns_io_t *io; |
| 17129 | dns_io_t *next; |
| 17130 | dns_zonemgr_t *zmgr; |
| 17131 | |
| 17132 | REQUIRE(iop != NULL); |
| 17133 | io = *iop; |
| 17134 | REQUIRE(DNS_IO_VALID(io)); |
| 17135 | |
| 17136 | *iop = NULL; |
| 17137 | |
| 17138 | INSIST(!ISC_LINK_LINKED(io, link)); |
| 17139 | INSIST(io->event == NULL); |
| 17140 | |
| 17141 | zmgr = io->zmgr; |
| 17142 | isc_task_detach(&io->task); |
| 17143 | io->magic = 0; |
| 17144 | isc_mem_put(zmgr->mctx, io, sizeof(*io)); |
| 17145 | |
| 17146 | LOCK(&zmgr->iolock); |
| 17147 | INSIST(zmgr->ioactive > 0); |
| 17148 | zmgr->ioactive--; |
| 17149 | next = HEAD(zmgr->high); |
| 17150 | if (next == NULL) |
| 17151 | next = HEAD(zmgr->low); |
| 17152 | if (next != NULL) { |
| 17153 | if (next->high) |
| 17154 | ISC_LIST_UNLINK(zmgr->high, next, link); |
| 17155 | else |
| 17156 | ISC_LIST_UNLINK(zmgr->low, next, link); |
| 17157 | INSIST(next->event != NULL); |
| 17158 | } |
| 17159 | UNLOCK(&zmgr->iolock); |
| 17160 | if (next != NULL) |
| 17161 | isc_task_send(next->task, &next->event); |
| 17162 | } |
| 17163 | |
| 17164 | static void |
| 17165 | zonemgr_cancelio(dns_io_t *io) { |
| 17166 | bool send_event = false; |
| 17167 | |
| 17168 | REQUIRE(DNS_IO_VALID(io)); |
| 17169 | |
| 17170 | /* |
| 17171 | * If we are queued to be run then dequeue. |
| 17172 | */ |
| 17173 | LOCK(&io->zmgr->iolock); |
| 17174 | if (ISC_LINK_LINKED(io, link)) { |
| 17175 | if (io->high) |
| 17176 | ISC_LIST_UNLINK(io->zmgr->high, io, link); |
| 17177 | else |
| 17178 | ISC_LIST_UNLINK(io->zmgr->low, io, link); |
| 17179 | |
| 17180 | send_event = true; |
| 17181 | INSIST(io->event != NULL); |
| 17182 | } |
| 17183 | UNLOCK(&io->zmgr->iolock); |
| 17184 | if (send_event) { |
| 17185 | io->event->ev_attributes |= ISC_EVENTATTR_CANCELED; |
| 17186 | isc_task_send(io->task, &io->event); |
| 17187 | } |
| 17188 | } |
| 17189 | |
| 17190 | static void |
| 17191 | zone_saveunique(dns_zone_t *zone, const char *path, const char *templat) { |
| 17192 | char *buf; |
| 17193 | int buflen; |
| 17194 | isc_result_t result; |
| 17195 | |
| 17196 | buflen = strlen(path) + strlen(templat) + 2; |
| 17197 | |
| 17198 | buf = isc_mem_get(zone->mctx, buflen); |
| 17199 | if (buf == NULL) |
| 17200 | return; |
| 17201 | |
| 17202 | result = isc_file_template(path, templat, buf, buflen); |
| 17203 | if (result != ISC_R_SUCCESS) |
| 17204 | goto cleanup; |
| 17205 | |
| 17206 | result = isc_file_renameunique(path, buf); |
| 17207 | if (result != ISC_R_SUCCESS) |
| 17208 | goto cleanup; |
| 17209 | |
| 17210 | dns_zone_log(zone, ISC_LOG_WARNING, "unable to load from '%s'; " |
| 17211 | "renaming file to '%s' for failure analysis and " |
| 17212 | "retransferring." , path, buf); |
| 17213 | |
| 17214 | cleanup: |
| 17215 | isc_mem_put(zone->mctx, buf, buflen); |
| 17216 | } |
| 17217 | |
| 17218 | static void |
| 17219 | setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value) { |
| 17220 | isc_interval_t interval; |
| 17221 | uint32_t s, ns; |
| 17222 | uint32_t pertic; |
| 17223 | isc_result_t result; |
| 17224 | |
| 17225 | if (value == 0) |
| 17226 | value = 1; |
| 17227 | |
| 17228 | if (value == 1) { |
| 17229 | s = 1; |
| 17230 | ns = 0; |
| 17231 | pertic = 1; |
| 17232 | } else if (value <= 10) { |
| 17233 | s = 0; |
| 17234 | ns = 1000000000 / value; |
| 17235 | pertic = 1; |
| 17236 | } else { |
| 17237 | s = 0; |
| 17238 | ns = (1000000000 / value) * 10; |
| 17239 | pertic = 10; |
| 17240 | } |
| 17241 | |
| 17242 | isc_interval_set(&interval, s, ns); |
| 17243 | |
| 17244 | result = isc_ratelimiter_setinterval(rl, &interval); |
| 17245 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 17246 | isc_ratelimiter_setpertic(rl, pertic); |
| 17247 | |
| 17248 | *rate = value; |
| 17249 | } |
| 17250 | |
| 17251 | void |
| 17252 | dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) { |
| 17253 | |
| 17254 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17255 | |
| 17256 | setrl(zmgr->notifyrl, &zmgr->notifyrate, value); |
| 17257 | } |
| 17258 | |
| 17259 | void |
| 17260 | dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) { |
| 17261 | |
| 17262 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17263 | |
| 17264 | setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, value); |
| 17265 | } |
| 17266 | |
| 17267 | void |
| 17268 | dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) { |
| 17269 | |
| 17270 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17271 | |
| 17272 | setrl(zmgr->refreshrl, &zmgr->serialqueryrate, value); |
| 17273 | /* XXXMPA seperate out once we have the code to support this. */ |
| 17274 | setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, value); |
| 17275 | } |
| 17276 | |
| 17277 | unsigned int |
| 17278 | dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr) { |
| 17279 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17280 | |
| 17281 | return (zmgr->notifyrate); |
| 17282 | } |
| 17283 | |
| 17284 | unsigned int |
| 17285 | dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr) { |
| 17286 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17287 | |
| 17288 | return (zmgr->startupnotifyrate); |
| 17289 | } |
| 17290 | |
| 17291 | unsigned int |
| 17292 | dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) { |
| 17293 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17294 | |
| 17295 | return (zmgr->serialqueryrate); |
| 17296 | } |
| 17297 | |
| 17298 | bool |
| 17299 | dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, |
| 17300 | isc_sockaddr_t *local, isc_time_t *now) |
| 17301 | { |
| 17302 | unsigned int i; |
| 17303 | isc_rwlocktype_t locktype; |
| 17304 | isc_result_t result; |
| 17305 | uint32_t seconds = isc_time_seconds(now); |
| 17306 | uint32_t count = 0; |
| 17307 | |
| 17308 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17309 | |
| 17310 | locktype = isc_rwlocktype_read; |
| 17311 | RWLOCK(&zmgr->urlock, locktype); |
| 17312 | for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { |
| 17313 | if (zmgr->unreachable[i].expire >= seconds && |
| 17314 | isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && |
| 17315 | isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { |
| 17316 | result = isc_rwlock_tryupgrade(&zmgr->urlock); |
| 17317 | if (result == ISC_R_SUCCESS) { |
| 17318 | locktype = isc_rwlocktype_write; |
| 17319 | zmgr->unreachable[i].last = seconds; |
| 17320 | count = zmgr->unreachable[i].count; |
| 17321 | } |
| 17322 | break; |
| 17323 | } |
| 17324 | } |
| 17325 | RWUNLOCK(&zmgr->urlock, locktype); |
| 17326 | return (i < UNREACH_CHACHE_SIZE && count > 1U); |
| 17327 | } |
| 17328 | |
| 17329 | void |
| 17330 | dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, |
| 17331 | isc_sockaddr_t *local) |
| 17332 | { |
| 17333 | unsigned int i; |
| 17334 | isc_rwlocktype_t locktype; |
| 17335 | isc_result_t result; |
| 17336 | |
| 17337 | char master[ISC_SOCKADDR_FORMATSIZE]; |
| 17338 | char source[ISC_SOCKADDR_FORMATSIZE]; |
| 17339 | |
| 17340 | isc_sockaddr_format(remote, master, sizeof(master)); |
| 17341 | isc_sockaddr_format(local, source, sizeof(source)); |
| 17342 | |
| 17343 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17344 | |
| 17345 | locktype = isc_rwlocktype_read; |
| 17346 | RWLOCK(&zmgr->urlock, locktype); |
| 17347 | for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { |
| 17348 | if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && |
| 17349 | isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { |
| 17350 | if (zmgr->unreachable[i].expire == 0) |
| 17351 | break; |
| 17352 | result = isc_rwlock_tryupgrade(&zmgr->urlock); |
| 17353 | if (result == ISC_R_SUCCESS) { |
| 17354 | locktype = isc_rwlocktype_write; |
| 17355 | zmgr->unreachable[i].expire = 0; |
| 17356 | isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, |
| 17357 | DNS_LOGMODULE_ZONE, ISC_LOG_INFO, |
| 17358 | "master %s (source %s) deleted " |
| 17359 | "from unreachable cache" , |
| 17360 | master, source); |
| 17361 | } |
| 17362 | break; |
| 17363 | } |
| 17364 | } |
| 17365 | RWUNLOCK(&zmgr->urlock, locktype); |
| 17366 | } |
| 17367 | |
| 17368 | void |
| 17369 | dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, |
| 17370 | isc_sockaddr_t *local, isc_time_t *now) |
| 17371 | { |
| 17372 | uint32_t seconds = isc_time_seconds(now); |
| 17373 | uint32_t last = seconds; |
| 17374 | unsigned int i, slot = UNREACH_CHACHE_SIZE, oldest = 0; |
| 17375 | |
| 17376 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17377 | |
| 17378 | RWLOCK(&zmgr->urlock, isc_rwlocktype_write); |
| 17379 | for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { |
| 17380 | /* Existing entry? */ |
| 17381 | if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && |
| 17382 | isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) |
| 17383 | break; |
| 17384 | /* Empty slot? */ |
| 17385 | if (zmgr->unreachable[i].expire < seconds) |
| 17386 | slot = i; |
| 17387 | /* Least recently used slot? */ |
| 17388 | if (zmgr->unreachable[i].last < last) { |
| 17389 | last = zmgr->unreachable[i].last; |
| 17390 | oldest = i; |
| 17391 | } |
| 17392 | } |
| 17393 | if (i < UNREACH_CHACHE_SIZE) { |
| 17394 | /* |
| 17395 | * Found a existing entry. Update the expire timer and |
| 17396 | * last usage timestamps. |
| 17397 | */ |
| 17398 | zmgr->unreachable[i].expire = seconds + UNREACH_HOLD_TIME; |
| 17399 | zmgr->unreachable[i].last = seconds; |
| 17400 | if (zmgr->unreachable[i].expire < seconds) |
| 17401 | zmgr->unreachable[i].count = 1; |
| 17402 | else |
| 17403 | zmgr->unreachable[i].count++; |
| 17404 | } else if (slot != UNREACH_CHACHE_SIZE) { |
| 17405 | /* |
| 17406 | * Found a empty slot. Add a new entry to the cache. |
| 17407 | */ |
| 17408 | zmgr->unreachable[slot].expire = seconds + UNREACH_HOLD_TIME; |
| 17409 | zmgr->unreachable[slot].last = seconds; |
| 17410 | zmgr->unreachable[slot].remote = *remote; |
| 17411 | zmgr->unreachable[slot].local = *local; |
| 17412 | zmgr->unreachable[slot].count = 1; |
| 17413 | } else { |
| 17414 | /* |
| 17415 | * Replace the least recently used entry in the cache. |
| 17416 | */ |
| 17417 | zmgr->unreachable[oldest].expire = seconds + UNREACH_HOLD_TIME; |
| 17418 | zmgr->unreachable[oldest].last = seconds; |
| 17419 | zmgr->unreachable[oldest].remote = *remote; |
| 17420 | zmgr->unreachable[oldest].local = *local; |
| 17421 | zmgr->unreachable[oldest].count = 1; |
| 17422 | } |
| 17423 | RWUNLOCK(&zmgr->urlock, isc_rwlocktype_write); |
| 17424 | } |
| 17425 | |
| 17426 | void |
| 17427 | dns_zone_forcereload(dns_zone_t *zone) { |
| 17428 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17429 | |
| 17430 | if (zone->type == dns_zone_master || |
| 17431 | (zone->type == dns_zone_redirect && zone->masters == NULL)) |
| 17432 | return; |
| 17433 | |
| 17434 | LOCK_ZONE(zone); |
| 17435 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FORCEXFER); |
| 17436 | UNLOCK_ZONE(zone); |
| 17437 | dns_zone_refresh(zone); |
| 17438 | } |
| 17439 | |
| 17440 | bool |
| 17441 | dns_zone_isforced(dns_zone_t *zone) { |
| 17442 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17443 | |
| 17444 | return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)); |
| 17445 | } |
| 17446 | |
| 17447 | isc_result_t |
| 17448 | dns_zone_setstatistics(dns_zone_t *zone, bool on) { |
| 17449 | /* |
| 17450 | * This function is obsoleted. |
| 17451 | */ |
| 17452 | UNUSED(zone); |
| 17453 | UNUSED(on); |
| 17454 | return (ISC_R_NOTIMPLEMENTED); |
| 17455 | } |
| 17456 | |
| 17457 | uint64_t * |
| 17458 | dns_zone_getstatscounters(dns_zone_t *zone) { |
| 17459 | /* |
| 17460 | * This function is obsoleted. |
| 17461 | */ |
| 17462 | UNUSED(zone); |
| 17463 | return (NULL); |
| 17464 | } |
| 17465 | |
| 17466 | void |
| 17467 | dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats) { |
| 17468 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17469 | REQUIRE(zone->stats == NULL); |
| 17470 | |
| 17471 | LOCK_ZONE(zone); |
| 17472 | zone->stats = NULL; |
| 17473 | isc_stats_attach(stats, &zone->stats); |
| 17474 | UNLOCK_ZONE(zone); |
| 17475 | } |
| 17476 | |
| 17477 | void |
| 17478 | dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) { |
| 17479 | |
| 17480 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17481 | |
| 17482 | LOCK_ZONE(zone); |
| 17483 | if (zone->requeststats_on && stats == NULL) |
| 17484 | zone->requeststats_on = false; |
| 17485 | else if (!zone->requeststats_on && stats != NULL) { |
| 17486 | if (zone->requeststats == NULL) { |
| 17487 | isc_stats_attach(stats, &zone->requeststats); |
| 17488 | zone->requeststats_on = true; |
| 17489 | } |
| 17490 | } |
| 17491 | UNLOCK_ZONE(zone); |
| 17492 | } |
| 17493 | |
| 17494 | void |
| 17495 | dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats) { |
| 17496 | |
| 17497 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17498 | |
| 17499 | LOCK_ZONE(zone); |
| 17500 | if (zone->requeststats_on && stats != NULL) { |
| 17501 | if (zone->rcvquerystats == NULL) { |
| 17502 | dns_stats_attach(stats, &zone->rcvquerystats); |
| 17503 | zone->requeststats_on = true; |
| 17504 | } |
| 17505 | } |
| 17506 | UNLOCK_ZONE(zone); |
| 17507 | } |
| 17508 | |
| 17509 | isc_stats_t * |
| 17510 | dns_zone_getrequeststats(dns_zone_t *zone) { |
| 17511 | /* |
| 17512 | * We don't lock zone for efficiency reason. This is not catastrophic |
| 17513 | * because requeststats must always be valid when requeststats_on is |
| 17514 | * true. |
| 17515 | * Some counters may be incremented while requeststats_on is becoming |
| 17516 | * false, or some cannot be incremented just after the statistics are |
| 17517 | * installed, but it shouldn't matter much in practice. |
| 17518 | */ |
| 17519 | if (zone->requeststats_on) |
| 17520 | return (zone->requeststats); |
| 17521 | else |
| 17522 | return (NULL); |
| 17523 | } |
| 17524 | |
| 17525 | /* |
| 17526 | * Return the received query stats bucket |
| 17527 | * see note from dns_zone_getrequeststats() |
| 17528 | */ |
| 17529 | dns_stats_t * |
| 17530 | dns_zone_getrcvquerystats(dns_zone_t *zone) { |
| 17531 | if (zone->requeststats_on) |
| 17532 | return (zone->rcvquerystats); |
| 17533 | else |
| 17534 | return (NULL); |
| 17535 | } |
| 17536 | |
| 17537 | void |
| 17538 | dns_zone_dialup(dns_zone_t *zone) { |
| 17539 | |
| 17540 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17541 | |
| 17542 | zone_debuglog(zone, "dns_zone_dialup" , 3, |
| 17543 | "notify = %d, refresh = %d" , |
| 17544 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY), |
| 17545 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)); |
| 17546 | |
| 17547 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY)) |
| 17548 | dns_zone_notify(zone); |
| 17549 | if (zone->type != dns_zone_master && zone->masters != NULL && |
| 17550 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) |
| 17551 | dns_zone_refresh(zone); |
| 17552 | } |
| 17553 | |
| 17554 | void |
| 17555 | dns_zone_setdialup(dns_zone_t *zone, dns_dialuptype_t dialup) { |
| 17556 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17557 | |
| 17558 | LOCK_ZONE(zone); |
| 17559 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DIALNOTIFY | |
| 17560 | DNS_ZONEFLG_DIALREFRESH | |
| 17561 | DNS_ZONEFLG_NOREFRESH); |
| 17562 | switch (dialup) { |
| 17563 | case dns_dialuptype_no: |
| 17564 | break; |
| 17565 | case dns_dialuptype_yes: |
| 17566 | DNS_ZONE_SETFLAG(zone, (DNS_ZONEFLG_DIALNOTIFY | |
| 17567 | DNS_ZONEFLG_DIALREFRESH | |
| 17568 | DNS_ZONEFLG_NOREFRESH)); |
| 17569 | break; |
| 17570 | case dns_dialuptype_notify: |
| 17571 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY); |
| 17572 | break; |
| 17573 | case dns_dialuptype_notifypassive: |
| 17574 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY); |
| 17575 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); |
| 17576 | break; |
| 17577 | case dns_dialuptype_refresh: |
| 17578 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALREFRESH); |
| 17579 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); |
| 17580 | break; |
| 17581 | case dns_dialuptype_passive: |
| 17582 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); |
| 17583 | break; |
| 17584 | default: |
| 17585 | INSIST(0); |
| 17586 | ISC_UNREACHABLE(); |
| 17587 | } |
| 17588 | UNLOCK_ZONE(zone); |
| 17589 | } |
| 17590 | |
| 17591 | isc_result_t |
| 17592 | dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory) { |
| 17593 | isc_result_t result = ISC_R_SUCCESS; |
| 17594 | |
| 17595 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17596 | |
| 17597 | LOCK_ZONE(zone); |
| 17598 | result = dns_zone_setstring(zone, &zone->keydirectory, directory); |
| 17599 | UNLOCK_ZONE(zone); |
| 17600 | |
| 17601 | return (result); |
| 17602 | } |
| 17603 | |
| 17604 | const char * |
| 17605 | dns_zone_getkeydirectory(dns_zone_t *zone) { |
| 17606 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17607 | |
| 17608 | return (zone->keydirectory); |
| 17609 | } |
| 17610 | |
| 17611 | unsigned int |
| 17612 | dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state) { |
| 17613 | dns_zone_t *zone; |
| 17614 | unsigned int count = 0; |
| 17615 | |
| 17616 | REQUIRE(DNS_ZONEMGR_VALID(zmgr)); |
| 17617 | |
| 17618 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); |
| 17619 | switch (state) { |
| 17620 | case DNS_ZONESTATE_XFERRUNNING: |
| 17621 | for (zone = ISC_LIST_HEAD(zmgr->xfrin_in_progress); |
| 17622 | zone != NULL; |
| 17623 | zone = ISC_LIST_NEXT(zone, statelink)) |
| 17624 | count++; |
| 17625 | break; |
| 17626 | case DNS_ZONESTATE_XFERDEFERRED: |
| 17627 | for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin); |
| 17628 | zone != NULL; |
| 17629 | zone = ISC_LIST_NEXT(zone, statelink)) |
| 17630 | count++; |
| 17631 | break; |
| 17632 | case DNS_ZONESTATE_SOAQUERY: |
| 17633 | for (zone = ISC_LIST_HEAD(zmgr->zones); |
| 17634 | zone != NULL; |
| 17635 | zone = ISC_LIST_NEXT(zone, link)) |
| 17636 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) |
| 17637 | count++; |
| 17638 | break; |
| 17639 | case DNS_ZONESTATE_ANY: |
| 17640 | for (zone = ISC_LIST_HEAD(zmgr->zones); |
| 17641 | zone != NULL; |
| 17642 | zone = ISC_LIST_NEXT(zone, link)) { |
| 17643 | dns_view_t *view = zone->view; |
| 17644 | if (view != NULL && strcmp(view->name, "_bind" ) == 0) |
| 17645 | continue; |
| 17646 | count++; |
| 17647 | } |
| 17648 | break; |
| 17649 | case DNS_ZONESTATE_AUTOMATIC: |
| 17650 | for (zone = ISC_LIST_HEAD(zmgr->zones); |
| 17651 | zone != NULL; |
| 17652 | zone = ISC_LIST_NEXT(zone, link)) { |
| 17653 | dns_view_t *view = zone->view; |
| 17654 | if (view != NULL && strcmp(view->name, "_bind" ) == 0) |
| 17655 | continue; |
| 17656 | if (zone->automatic) |
| 17657 | count++; |
| 17658 | } |
| 17659 | break; |
| 17660 | default: |
| 17661 | INSIST(0); |
| 17662 | ISC_UNREACHABLE(); |
| 17663 | } |
| 17664 | |
| 17665 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); |
| 17666 | |
| 17667 | return (count); |
| 17668 | } |
| 17669 | |
| 17670 | isc_result_t |
| 17671 | dns_zone_checknames(dns_zone_t *zone, const dns_name_t *name, |
| 17672 | dns_rdata_t *rdata) |
| 17673 | { |
| 17674 | bool ok = true; |
| 17675 | bool fail = false; |
| 17676 | char namebuf[DNS_NAME_FORMATSIZE]; |
| 17677 | char namebuf2[DNS_NAME_FORMATSIZE]; |
| 17678 | char typebuf[DNS_RDATATYPE_FORMATSIZE]; |
| 17679 | int level = ISC_LOG_WARNING; |
| 17680 | dns_name_t bad; |
| 17681 | |
| 17682 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17683 | |
| 17684 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES) && |
| 17685 | rdata->type != dns_rdatatype_nsec3) |
| 17686 | return (ISC_R_SUCCESS); |
| 17687 | |
| 17688 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL) || |
| 17689 | rdata->type == dns_rdatatype_nsec3) { |
| 17690 | level = ISC_LOG_ERROR; |
| 17691 | fail = true; |
| 17692 | } |
| 17693 | |
| 17694 | ok = dns_rdata_checkowner(name, rdata->rdclass, rdata->type, true); |
| 17695 | if (!ok) { |
| 17696 | dns_name_format(name, namebuf, sizeof(namebuf)); |
| 17697 | dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf)); |
| 17698 | dns_zone_log(zone, level, "%s/%s: %s" , namebuf, typebuf, |
| 17699 | dns_result_totext(DNS_R_BADOWNERNAME)); |
| 17700 | if (fail) |
| 17701 | return (DNS_R_BADOWNERNAME); |
| 17702 | } |
| 17703 | |
| 17704 | dns_name_init(&bad, NULL); |
| 17705 | ok = dns_rdata_checknames(rdata, name, &bad); |
| 17706 | if (!ok) { |
| 17707 | dns_name_format(name, namebuf, sizeof(namebuf)); |
| 17708 | dns_name_format(&bad, namebuf2, sizeof(namebuf2)); |
| 17709 | dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf)); |
| 17710 | dns_zone_log(zone, level, "%s/%s: %s: %s " , namebuf, typebuf, |
| 17711 | namebuf2, dns_result_totext(DNS_R_BADNAME)); |
| 17712 | if (fail) |
| 17713 | return (DNS_R_BADNAME); |
| 17714 | } |
| 17715 | |
| 17716 | return (ISC_R_SUCCESS); |
| 17717 | } |
| 17718 | |
| 17719 | void |
| 17720 | dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx) { |
| 17721 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17722 | zone->checkmx = checkmx; |
| 17723 | } |
| 17724 | |
| 17725 | void |
| 17726 | dns_zone_setchecksrv(dns_zone_t *zone, dns_checksrvfunc_t checksrv) { |
| 17727 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17728 | zone->checksrv = checksrv; |
| 17729 | } |
| 17730 | |
| 17731 | void |
| 17732 | dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns) { |
| 17733 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17734 | zone->checkns = checkns; |
| 17735 | } |
| 17736 | |
| 17737 | void |
| 17738 | dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg) { |
| 17739 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17740 | |
| 17741 | LOCK_ZONE(zone); |
| 17742 | zone->isself = isself; |
| 17743 | zone->isselfarg = arg; |
| 17744 | UNLOCK_ZONE(zone); |
| 17745 | } |
| 17746 | |
| 17747 | void |
| 17748 | dns_zone_setnotifydelay(dns_zone_t *zone, uint32_t delay) { |
| 17749 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17750 | |
| 17751 | LOCK_ZONE(zone); |
| 17752 | zone->notifydelay = delay; |
| 17753 | UNLOCK_ZONE(zone); |
| 17754 | } |
| 17755 | |
| 17756 | uint32_t |
| 17757 | dns_zone_getnotifydelay(dns_zone_t *zone) { |
| 17758 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17759 | |
| 17760 | return (zone->notifydelay); |
| 17761 | } |
| 17762 | |
| 17763 | isc_result_t |
| 17764 | dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, |
| 17765 | uint16_t keyid, bool deleteit) |
| 17766 | { |
| 17767 | isc_result_t result; |
| 17768 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17769 | |
| 17770 | dnssec_log(zone, ISC_LOG_NOTICE, |
| 17771 | "dns_zone_signwithkey(algorithm=%u, keyid=%u)" , |
| 17772 | algorithm, keyid); |
| 17773 | LOCK_ZONE(zone); |
| 17774 | result = zone_signwithkey(zone, algorithm, keyid, deleteit); |
| 17775 | UNLOCK_ZONE(zone); |
| 17776 | |
| 17777 | return (result); |
| 17778 | } |
| 17779 | |
| 17780 | /* |
| 17781 | * Called when a dynamic update for an NSEC3PARAM record is received. |
| 17782 | * |
| 17783 | * If set, transform the NSEC3 salt into human-readable form so that it can be |
| 17784 | * logged. Then call zone_addnsec3chain(), passing NSEC3PARAM RDATA to it. |
| 17785 | */ |
| 17786 | isc_result_t |
| 17787 | dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { |
| 17788 | isc_result_t result; |
| 17789 | char salt[255*2+1]; |
| 17790 | |
| 17791 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17792 | |
| 17793 | result = dns_nsec3param_salttotext(nsec3param, salt, sizeof(salt)); |
| 17794 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 17795 | dnssec_log(zone, ISC_LOG_NOTICE, |
| 17796 | "dns_zone_addnsec3chain(hash=%u, iterations=%u, salt=%s)" , |
| 17797 | nsec3param->hash, nsec3param->iterations, salt); |
| 17798 | LOCK_ZONE(zone); |
| 17799 | result = zone_addnsec3chain(zone, nsec3param); |
| 17800 | UNLOCK_ZONE(zone); |
| 17801 | |
| 17802 | return (result); |
| 17803 | } |
| 17804 | |
| 17805 | void |
| 17806 | dns_zone_setnodes(dns_zone_t *zone, uint32_t nodes) { |
| 17807 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17808 | |
| 17809 | if (nodes == 0) |
| 17810 | nodes = 1; |
| 17811 | zone->nodes = nodes; |
| 17812 | } |
| 17813 | |
| 17814 | void |
| 17815 | dns_zone_setsignatures(dns_zone_t *zone, uint32_t signatures) { |
| 17816 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17817 | |
| 17818 | /* |
| 17819 | * We treat signatures as a signed value so explicitly |
| 17820 | * limit its range here. |
| 17821 | */ |
| 17822 | if (signatures > INT32_MAX) |
| 17823 | signatures = INT32_MAX; |
| 17824 | else if (signatures == 0) |
| 17825 | signatures = 1; |
| 17826 | zone->signatures = signatures; |
| 17827 | } |
| 17828 | |
| 17829 | uint32_t |
| 17830 | dns_zone_getsignatures(dns_zone_t *zone) { |
| 17831 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17832 | return (zone->signatures); |
| 17833 | } |
| 17834 | |
| 17835 | void |
| 17836 | dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type) { |
| 17837 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17838 | zone->privatetype = type; |
| 17839 | } |
| 17840 | |
| 17841 | dns_rdatatype_t |
| 17842 | dns_zone_getprivatetype(dns_zone_t *zone) { |
| 17843 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 17844 | return (zone->privatetype); |
| 17845 | } |
| 17846 | |
| 17847 | static isc_result_t |
| 17848 | zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid, |
| 17849 | bool deleteit) |
| 17850 | { |
| 17851 | dns_signing_t *signing; |
| 17852 | dns_signing_t *current; |
| 17853 | isc_result_t result = ISC_R_SUCCESS; |
| 17854 | isc_time_t now; |
| 17855 | dns_db_t *db = NULL; |
| 17856 | |
| 17857 | signing = isc_mem_get(zone->mctx, sizeof *signing); |
| 17858 | if (signing == NULL) |
| 17859 | return (ISC_R_NOMEMORY); |
| 17860 | |
| 17861 | signing->magic = 0; |
| 17862 | signing->db = NULL; |
| 17863 | signing->dbiterator = NULL; |
| 17864 | signing->algorithm = algorithm; |
| 17865 | signing->keyid = keyid; |
| 17866 | signing->deleteit = deleteit; |
| 17867 | signing->done = false; |
| 17868 | |
| 17869 | TIME_NOW(&now); |
| 17870 | |
| 17871 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 17872 | if (zone->db != NULL) |
| 17873 | dns_db_attach(zone->db, &db); |
| 17874 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 17875 | |
| 17876 | if (db == NULL) { |
| 17877 | result = ISC_R_NOTFOUND; |
| 17878 | goto cleanup; |
| 17879 | } |
| 17880 | |
| 17881 | dns_db_attach(db, &signing->db); |
| 17882 | |
| 17883 | for (current = ISC_LIST_HEAD(zone->signing); |
| 17884 | current != NULL; |
| 17885 | current = ISC_LIST_NEXT(current, link)) { |
| 17886 | if (current->db == signing->db && |
| 17887 | current->algorithm == signing->algorithm && |
| 17888 | current->keyid == signing->keyid) { |
| 17889 | if (current->deleteit != signing->deleteit) |
| 17890 | current->done = true; |
| 17891 | else |
| 17892 | goto cleanup; |
| 17893 | } |
| 17894 | } |
| 17895 | |
| 17896 | result = dns_db_createiterator(signing->db, 0, |
| 17897 | &signing->dbiterator); |
| 17898 | |
| 17899 | if (result == ISC_R_SUCCESS) |
| 17900 | result = dns_dbiterator_first(signing->dbiterator); |
| 17901 | if (result == ISC_R_SUCCESS) { |
| 17902 | dns_dbiterator_pause(signing->dbiterator); |
| 17903 | ISC_LIST_INITANDAPPEND(zone->signing, signing, link); |
| 17904 | signing = NULL; |
| 17905 | if (isc_time_isepoch(&zone->signingtime)) { |
| 17906 | zone->signingtime = now; |
| 17907 | if (zone->task != NULL) |
| 17908 | zone_settimer(zone, &now); |
| 17909 | } |
| 17910 | } |
| 17911 | |
| 17912 | cleanup: |
| 17913 | if (signing != NULL) { |
| 17914 | if (signing->db != NULL) |
| 17915 | dns_db_detach(&signing->db); |
| 17916 | if (signing->dbiterator != NULL) |
| 17917 | dns_dbiterator_destroy(&signing->dbiterator); |
| 17918 | isc_mem_put(zone->mctx, signing, sizeof *signing); |
| 17919 | } |
| 17920 | if (db != NULL) |
| 17921 | dns_db_detach(&db); |
| 17922 | return (result); |
| 17923 | } |
| 17924 | |
| 17925 | static void |
| 17926 | clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) { |
| 17927 | dns_dnsseckey_t *key; |
| 17928 | while (!ISC_LIST_EMPTY(*list)) { |
| 17929 | key = ISC_LIST_HEAD(*list); |
| 17930 | ISC_LIST_UNLINK(*list, key, link); |
| 17931 | dns_dnsseckey_destroy(mctx, &key); |
| 17932 | } |
| 17933 | } |
| 17934 | |
| 17935 | /* Called once; *timep should be set to the current time. */ |
| 17936 | static isc_result_t |
| 17937 | next_keyevent(dst_key_t *key, isc_stdtime_t *timep) { |
| 17938 | isc_result_t result; |
| 17939 | isc_stdtime_t now, then = 0, event; |
| 17940 | int i; |
| 17941 | |
| 17942 | now = *timep; |
| 17943 | |
| 17944 | for (i = 0; i <= DST_MAX_TIMES; i++) { |
| 17945 | result = dst_key_gettime(key, i, &event); |
| 17946 | if (result == ISC_R_SUCCESS && event > now && |
| 17947 | (then == 0 || event < then)) |
| 17948 | then = event; |
| 17949 | } |
| 17950 | |
| 17951 | if (then != 0) { |
| 17952 | *timep = then; |
| 17953 | return (ISC_R_SUCCESS); |
| 17954 | } |
| 17955 | |
| 17956 | return (ISC_R_NOTFOUND); |
| 17957 | } |
| 17958 | |
| 17959 | static isc_result_t |
| 17960 | rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, |
| 17961 | const dns_rdata_t *rdata, bool *flag) |
| 17962 | { |
| 17963 | dns_rdataset_t rdataset; |
| 17964 | dns_dbnode_t *node = NULL; |
| 17965 | isc_result_t result; |
| 17966 | |
| 17967 | dns_rdataset_init(&rdataset); |
| 17968 | if (rdata->type == dns_rdatatype_nsec3) |
| 17969 | CHECK(dns_db_findnsec3node(db, name, false, &node)); |
| 17970 | else |
| 17971 | CHECK(dns_db_findnode(db, name, false, &node)); |
| 17972 | result = dns_db_findrdataset(db, node, ver, rdata->type, 0, |
| 17973 | (isc_stdtime_t) 0, &rdataset, NULL); |
| 17974 | if (result == ISC_R_NOTFOUND) { |
| 17975 | *flag = false; |
| 17976 | result = ISC_R_SUCCESS; |
| 17977 | goto failure; |
| 17978 | } |
| 17979 | |
| 17980 | for (result = dns_rdataset_first(&rdataset); |
| 17981 | result == ISC_R_SUCCESS; |
| 17982 | result = dns_rdataset_next(&rdataset)) { |
| 17983 | dns_rdata_t myrdata = DNS_RDATA_INIT; |
| 17984 | dns_rdataset_current(&rdataset, &myrdata); |
| 17985 | if (!dns_rdata_compare(&myrdata, rdata)) |
| 17986 | break; |
| 17987 | } |
| 17988 | dns_rdataset_disassociate(&rdataset); |
| 17989 | if (result == ISC_R_SUCCESS) { |
| 17990 | *flag = true; |
| 17991 | } else if (result == ISC_R_NOMORE) { |
| 17992 | *flag = false; |
| 17993 | result = ISC_R_SUCCESS; |
| 17994 | } |
| 17995 | |
| 17996 | failure: |
| 17997 | if (node != NULL) |
| 17998 | dns_db_detachnode(db, &node); |
| 17999 | return (result); |
| 18000 | } |
| 18001 | |
| 18002 | /* |
| 18003 | * Add records to signal the state of signing or of key removal. |
| 18004 | */ |
| 18005 | static isc_result_t |
| 18006 | add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype, |
| 18007 | dns_dbversion_t *ver, dns_diff_t *diff, |
| 18008 | bool sign_all) |
| 18009 | { |
| 18010 | dns_difftuple_t *tuple, *newtuple = NULL; |
| 18011 | dns_rdata_dnskey_t dnskey; |
| 18012 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 18013 | bool flag; |
| 18014 | isc_region_t r; |
| 18015 | isc_result_t result = ISC_R_SUCCESS; |
| 18016 | uint16_t keyid; |
| 18017 | unsigned char buf[5]; |
| 18018 | dns_name_t *name = dns_db_origin(db); |
| 18019 | |
| 18020 | for (tuple = ISC_LIST_HEAD(diff->tuples); |
| 18021 | tuple != NULL; |
| 18022 | tuple = ISC_LIST_NEXT(tuple, link)) { |
| 18023 | if (tuple->rdata.type != dns_rdatatype_dnskey) |
| 18024 | continue; |
| 18025 | |
| 18026 | result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL); |
| 18027 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 18028 | if ((dnskey.flags & |
| 18029 | (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) |
| 18030 | != DNS_KEYOWNER_ZONE) |
| 18031 | continue; |
| 18032 | |
| 18033 | dns_rdata_toregion(&tuple->rdata, &r); |
| 18034 | |
| 18035 | keyid = dst_region_computeid(&r); |
| 18036 | |
| 18037 | buf[0] = dnskey.algorithm; |
| 18038 | buf[1] = (keyid & 0xff00) >> 8; |
| 18039 | buf[2] = (keyid & 0xff); |
| 18040 | buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1; |
| 18041 | buf[4] = 0; |
| 18042 | rdata.data = buf; |
| 18043 | rdata.length = sizeof(buf); |
| 18044 | rdata.type = privatetype; |
| 18045 | rdata.rdclass = tuple->rdata.rdclass; |
| 18046 | |
| 18047 | if (sign_all || tuple->op == DNS_DIFFOP_DEL) { |
| 18048 | CHECK(rr_exists(db, ver, name, &rdata, &flag)); |
| 18049 | if (flag) |
| 18050 | continue; |
| 18051 | CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, |
| 18052 | name, 0, &rdata, &newtuple)); |
| 18053 | CHECK(do_one_tuple(&newtuple, db, ver, diff)); |
| 18054 | INSIST(newtuple == NULL); |
| 18055 | } |
| 18056 | |
| 18057 | /* |
| 18058 | * Remove any record which says this operation has already |
| 18059 | * completed. |
| 18060 | */ |
| 18061 | buf[4] = 1; |
| 18062 | CHECK(rr_exists(db, ver, name, &rdata, &flag)); |
| 18063 | if (flag) { |
| 18064 | CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, |
| 18065 | name, 0, &rdata, &newtuple)); |
| 18066 | CHECK(do_one_tuple(&newtuple, db, ver, diff)); |
| 18067 | INSIST(newtuple == NULL); |
| 18068 | } |
| 18069 | } |
| 18070 | failure: |
| 18071 | return (result); |
| 18072 | } |
| 18073 | |
| 18074 | static isc_result_t |
| 18075 | sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
| 18076 | isc_stdtime_t now, dns_diff_t *diff, dns__zonediff_t *zonediff) |
| 18077 | { |
| 18078 | isc_result_t result; |
| 18079 | isc_stdtime_t inception, soaexpire, keyexpire; |
| 18080 | bool check_ksk, keyset_kskonly; |
| 18081 | dst_key_t *zone_keys[DNS_MAXZONEKEYS]; |
| 18082 | unsigned int nkeys = 0, i; |
| 18083 | dns_difftuple_t *tuple; |
| 18084 | |
| 18085 | result = dns__zone_findkeys(zone, db, ver, now, zone->mctx, |
| 18086 | DNS_MAXZONEKEYS, zone_keys, &nkeys); |
| 18087 | if (result != ISC_R_SUCCESS) { |
| 18088 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18089 | "sign_apex:dns__zone_findkeys -> %s" , |
| 18090 | dns_result_totext(result)); |
| 18091 | return (result); |
| 18092 | } |
| 18093 | |
| 18094 | inception = now - 3600; /* Allow for clock skew. */ |
| 18095 | soaexpire = now + dns_zone_getsigvalidityinterval(zone); |
| 18096 | |
| 18097 | keyexpire = dns_zone_getkeyvalidityinterval(zone); |
| 18098 | if (keyexpire == 0) { |
| 18099 | keyexpire = soaexpire - 1; |
| 18100 | } else { |
| 18101 | keyexpire += now; |
| 18102 | } |
| 18103 | |
| 18104 | check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); |
| 18105 | keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); |
| 18106 | |
| 18107 | /* |
| 18108 | * See if dns__zone_updatesigs() will update DNSKEY signature and if |
| 18109 | * not cause them to sign so that newly activated keys are used. |
| 18110 | */ |
| 18111 | for (tuple = ISC_LIST_HEAD(diff->tuples); |
| 18112 | tuple != NULL; |
| 18113 | tuple = ISC_LIST_NEXT(tuple, link)) |
| 18114 | { |
| 18115 | if (tuple->rdata.type == dns_rdatatype_dnskey && |
| 18116 | dns_name_equal(&tuple->name, &zone->origin)) |
| 18117 | { |
| 18118 | break; |
| 18119 | } |
| 18120 | } |
| 18121 | |
| 18122 | if (tuple == NULL) { |
| 18123 | result = del_sigs(zone, db, ver, &zone->origin, |
| 18124 | dns_rdatatype_dnskey, zonediff, |
| 18125 | zone_keys, nkeys, now, false); |
| 18126 | if (result != ISC_R_SUCCESS) { |
| 18127 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18128 | "sign_apex:del_sigs -> %s" , |
| 18129 | dns_result_totext(result)); |
| 18130 | goto failure; |
| 18131 | } |
| 18132 | result = add_sigs(db, ver, &zone->origin, dns_rdatatype_dnskey, |
| 18133 | zonediff->diff, zone_keys, nkeys, zone->mctx, |
| 18134 | inception, keyexpire, check_ksk, |
| 18135 | keyset_kskonly); |
| 18136 | if (result != ISC_R_SUCCESS) { |
| 18137 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18138 | "sign_apex:add_sigs -> %s" , |
| 18139 | dns_result_totext(result)); |
| 18140 | goto failure; |
| 18141 | } |
| 18142 | } |
| 18143 | |
| 18144 | result = dns__zone_updatesigs(diff, db, ver, zone_keys, nkeys, zone, |
| 18145 | inception, soaexpire, keyexpire, now, |
| 18146 | check_ksk, keyset_kskonly, zonediff); |
| 18147 | |
| 18148 | if (result != ISC_R_SUCCESS) { |
| 18149 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18150 | "sign_apex:dns__zone_updatesigs -> %s" , |
| 18151 | dns_result_totext(result)); |
| 18152 | goto failure; |
| 18153 | } |
| 18154 | |
| 18155 | failure: |
| 18156 | for (i = 0; i < nkeys; i++) { |
| 18157 | dst_key_free(&zone_keys[i]); |
| 18158 | } |
| 18159 | return (result); |
| 18160 | } |
| 18161 | |
| 18162 | /* |
| 18163 | * Prevent the zone entering a inconsistent state where |
| 18164 | * NSEC only DNSKEYs are present with NSEC3 chains. |
| 18165 | * See update.c:check_dnssec() |
| 18166 | */ |
| 18167 | static bool |
| 18168 | dnskey_sane(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
| 18169 | dns_diff_t *diff) |
| 18170 | { |
| 18171 | isc_result_t result; |
| 18172 | dns_difftuple_t *tuple; |
| 18173 | bool nseconly = false, nsec3 = false; |
| 18174 | dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); |
| 18175 | |
| 18176 | /* Scan the tuples for an NSEC-only DNSKEY */ |
| 18177 | for (tuple = ISC_LIST_HEAD(diff->tuples); |
| 18178 | tuple != NULL; |
| 18179 | tuple = ISC_LIST_NEXT(tuple, link)) |
| 18180 | { |
| 18181 | uint8_t alg; |
| 18182 | if (tuple->rdata.type != dns_rdatatype_dnskey || |
| 18183 | tuple->op != DNS_DIFFOP_ADD) |
| 18184 | { |
| 18185 | continue; |
| 18186 | } |
| 18187 | |
| 18188 | alg = tuple->rdata.data[3]; |
| 18189 | if (alg == DST_ALG_RSASHA1) { |
| 18190 | nseconly = true; |
| 18191 | break; |
| 18192 | } |
| 18193 | } |
| 18194 | |
| 18195 | /* Check existing DB for NSEC-only DNSKEY */ |
| 18196 | if (!nseconly) { |
| 18197 | result = dns_nsec_nseconly(db, ver, &nseconly); |
| 18198 | if (result == ISC_R_NOTFOUND) { |
| 18199 | result = ISC_R_SUCCESS; |
| 18200 | } |
| 18201 | CHECK(result); |
| 18202 | } |
| 18203 | |
| 18204 | /* Check existing DB for NSEC3 */ |
| 18205 | if (!nsec3) { |
| 18206 | CHECK(dns_nsec3_activex(db, ver, false, |
| 18207 | privatetype, &nsec3)); |
| 18208 | } |
| 18209 | |
| 18210 | /* Refuse to allow NSEC3 with NSEC-only keys */ |
| 18211 | if (nseconly && nsec3) { |
| 18212 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18213 | "NSEC only DNSKEYs and NSEC3 chains not allowed" ); |
| 18214 | goto failure; |
| 18215 | } |
| 18216 | |
| 18217 | return (true); |
| 18218 | |
| 18219 | failure: |
| 18220 | return (false); |
| 18221 | } |
| 18222 | |
| 18223 | static isc_result_t |
| 18224 | clean_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
| 18225 | dns_diff_t *diff) |
| 18226 | { |
| 18227 | isc_result_t result; |
| 18228 | dns_dbnode_t *node = NULL; |
| 18229 | dns_rdataset_t rdataset; |
| 18230 | |
| 18231 | dns_rdataset_init(&rdataset); |
| 18232 | CHECK(dns_db_getoriginnode(db, &node)); |
| 18233 | |
| 18234 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, |
| 18235 | dns_rdatatype_none, 0, &rdataset, NULL); |
| 18236 | if (dns_rdataset_isassociated(&rdataset)) |
| 18237 | dns_rdataset_disassociate(&rdataset); |
| 18238 | if (result != ISC_R_NOTFOUND) |
| 18239 | goto failure; |
| 18240 | |
| 18241 | result = dns_nsec3param_deletechains(db, ver, zone, true, diff); |
| 18242 | |
| 18243 | failure: |
| 18244 | if (node != NULL) |
| 18245 | dns_db_detachnode(db, &node); |
| 18246 | return (result); |
| 18247 | } |
| 18248 | |
| 18249 | /* |
| 18250 | * Given an RRSIG rdataset and an algorithm, determine whether there |
| 18251 | * are any signatures using that algorithm. |
| 18252 | */ |
| 18253 | static bool |
| 18254 | signed_with_alg(dns_rdataset_t *rdataset, dns_secalg_t alg) { |
| 18255 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 18256 | dns_rdata_rrsig_t rrsig; |
| 18257 | isc_result_t result; |
| 18258 | |
| 18259 | REQUIRE(rdataset == NULL || rdataset->type == dns_rdatatype_rrsig); |
| 18260 | if (rdataset == NULL || !dns_rdataset_isassociated(rdataset)) { |
| 18261 | return (false); |
| 18262 | } |
| 18263 | |
| 18264 | for (result = dns_rdataset_first(rdataset); |
| 18265 | result == ISC_R_SUCCESS; |
| 18266 | result = dns_rdataset_next(rdataset)) |
| 18267 | { |
| 18268 | dns_rdataset_current(rdataset, &rdata); |
| 18269 | result = dns_rdata_tostruct(&rdata, &rrsig, NULL); |
| 18270 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 18271 | dns_rdata_reset(&rdata); |
| 18272 | if (rrsig.algorithm == alg) |
| 18273 | return (true); |
| 18274 | } |
| 18275 | |
| 18276 | return (false); |
| 18277 | } |
| 18278 | |
| 18279 | static isc_result_t |
| 18280 | add_chains(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
| 18281 | dns_diff_t *diff) |
| 18282 | { |
| 18283 | dns_name_t *origin; |
| 18284 | bool build_nsec3; |
| 18285 | isc_result_t result; |
| 18286 | |
| 18287 | origin = dns_db_origin(db); |
| 18288 | CHECK(dns_private_chains(db, ver, zone->privatetype, NULL, |
| 18289 | &build_nsec3)); |
| 18290 | if (build_nsec3) |
| 18291 | CHECK(dns_nsec3_addnsec3sx(db, ver, origin, zone->minimum, |
| 18292 | false, zone->privatetype, diff)); |
| 18293 | CHECK(updatesecure(db, ver, origin, zone->minimum, true, diff)); |
| 18294 | |
| 18295 | failure: |
| 18296 | return (result); |
| 18297 | } |
| 18298 | |
| 18299 | static void |
| 18300 | dnssec_report(const char *format, ...) { |
| 18301 | va_list args; |
| 18302 | va_start(args, format); |
| 18303 | isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_ZONE, |
| 18304 | ISC_LOG_INFO, format, args); |
| 18305 | va_end(args); |
| 18306 | } |
| 18307 | |
| 18308 | static void |
| 18309 | zone_rekey(dns_zone_t *zone) { |
| 18310 | isc_result_t result; |
| 18311 | dns_db_t *db = NULL; |
| 18312 | dns_dbnode_t *node = NULL; |
| 18313 | dns_dbversion_t *ver = NULL; |
| 18314 | dns_rdataset_t cdsset, soaset, soasigs, keyset, keysigs, cdnskeyset; |
| 18315 | dns_dnsseckeylist_t dnskeys, keys, rmkeys; |
| 18316 | dns_dnsseckey_t *key = NULL; |
| 18317 | dns_diff_t diff, _sig_diff; |
| 18318 | dns__zonediff_t zonediff; |
| 18319 | bool commit = false, newactive = false; |
| 18320 | bool newalg = false; |
| 18321 | bool fullsign; |
| 18322 | dns_ttl_t ttl = 3600; |
| 18323 | const char *dir = NULL; |
| 18324 | isc_mem_t *mctx = NULL; |
| 18325 | isc_stdtime_t now; |
| 18326 | isc_time_t timenow; |
| 18327 | isc_interval_t ival; |
| 18328 | char timebuf[80]; |
| 18329 | |
| 18330 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18331 | |
| 18332 | ISC_LIST_INIT(dnskeys); |
| 18333 | ISC_LIST_INIT(keys); |
| 18334 | ISC_LIST_INIT(rmkeys); |
| 18335 | dns_rdataset_init(&soaset); |
| 18336 | dns_rdataset_init(&soasigs); |
| 18337 | dns_rdataset_init(&keyset); |
| 18338 | dns_rdataset_init(&keysigs); |
| 18339 | dns_rdataset_init(&cdsset); |
| 18340 | dns_rdataset_init(&cdnskeyset); |
| 18341 | dir = dns_zone_getkeydirectory(zone); |
| 18342 | mctx = zone->mctx; |
| 18343 | dns_diff_init(mctx, &diff); |
| 18344 | dns_diff_init(mctx, &_sig_diff); |
| 18345 | zonediff_init(&zonediff, &_sig_diff); |
| 18346 | |
| 18347 | CHECK(dns_zone_getdb(zone, &db)); |
| 18348 | CHECK(dns_db_newversion(db, &ver)); |
| 18349 | CHECK(dns_db_getoriginnode(db, &node)); |
| 18350 | |
| 18351 | TIME_NOW(&timenow); |
| 18352 | now = isc_time_seconds(&timenow); |
| 18353 | |
| 18354 | dnssec_log(zone, ISC_LOG_INFO, "reconfiguring zone keys" ); |
| 18355 | |
| 18356 | /* Get the SOA record's TTL */ |
| 18357 | CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, |
| 18358 | dns_rdatatype_none, 0, &soaset, &soasigs)); |
| 18359 | ttl = soaset.ttl; |
| 18360 | dns_rdataset_disassociate(&soaset); |
| 18361 | |
| 18362 | /* Get the DNSKEY rdataset */ |
| 18363 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, |
| 18364 | dns_rdatatype_none, 0, &keyset, &keysigs); |
| 18365 | if (result == ISC_R_SUCCESS) { |
| 18366 | ttl = keyset.ttl; |
| 18367 | CHECK(dns_dnssec_keylistfromrdataset(&zone->origin, dir, |
| 18368 | mctx, &keyset, |
| 18369 | &keysigs, &soasigs, |
| 18370 | false, false, |
| 18371 | &dnskeys)); |
| 18372 | } else if (result != ISC_R_NOTFOUND) { |
| 18373 | goto failure; |
| 18374 | } |
| 18375 | |
| 18376 | |
| 18377 | /* Get the CDS rdataset */ |
| 18378 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_cds, |
| 18379 | dns_rdatatype_none, 0, &cdsset, NULL); |
| 18380 | if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdsset)) |
| 18381 | dns_rdataset_disassociate(&cdsset); |
| 18382 | |
| 18383 | /* Get the CDNSKEY rdataset */ |
| 18384 | result = dns_db_findrdataset(db, node, ver, dns_rdatatype_cdnskey, |
| 18385 | dns_rdatatype_none, 0, &cdnskeyset, NULL); |
| 18386 | if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdnskeyset)) |
| 18387 | { |
| 18388 | dns_rdataset_disassociate(&cdnskeyset); |
| 18389 | } |
| 18390 | |
| 18391 | /* |
| 18392 | * True when called from "rndc sign". Indicates the zone should be |
| 18393 | * fully signed now. |
| 18394 | */ |
| 18395 | fullsign = DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_FULLSIGN); |
| 18396 | |
| 18397 | result = dns_dnssec_findmatchingkeys(&zone->origin, dir, now, mctx, |
| 18398 | &keys); |
| 18399 | if (result == ISC_R_SUCCESS) { |
| 18400 | bool check_ksk; |
| 18401 | check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); |
| 18402 | |
| 18403 | result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys, |
| 18404 | &zone->origin, ttl, &diff, |
| 18405 | !check_ksk, mctx, |
| 18406 | dnssec_report); |
| 18407 | /* |
| 18408 | * Keys couldn't be updated for some reason; |
| 18409 | * try again later. |
| 18410 | */ |
| 18411 | if (result != ISC_R_SUCCESS) { |
| 18412 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18413 | "zone_rekey:couldn't update zone keys: %s" , |
| 18414 | isc_result_totext(result)); |
| 18415 | goto failure; |
| 18416 | } |
| 18417 | |
| 18418 | /* |
| 18419 | * Update CDS / CDNSKEY records. |
| 18420 | */ |
| 18421 | result = dns_dnssec_syncupdate(&dnskeys, &rmkeys, &cdsset, |
| 18422 | &cdnskeyset, now, ttl, |
| 18423 | &diff, mctx); |
| 18424 | if (result != ISC_R_SUCCESS) { |
| 18425 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18426 | "zone_rekey:couldn't update CDS/CDNSKEY: %s" , |
| 18427 | isc_result_totext(result)); |
| 18428 | goto failure; |
| 18429 | } |
| 18430 | |
| 18431 | /* |
| 18432 | * See if any pre-existing keys have newly become active; |
| 18433 | * also, see if any new key is for a new algorithm, as in that |
| 18434 | * event, we need to sign the zone fully. (If there's a new |
| 18435 | * key, but it's for an already-existing algorithm, then |
| 18436 | * the zone signing can be handled incrementally.) |
| 18437 | */ |
| 18438 | for (key = ISC_LIST_HEAD(dnskeys); |
| 18439 | key != NULL; |
| 18440 | key = ISC_LIST_NEXT(key, link)) |
| 18441 | { |
| 18442 | if (!key->first_sign) { |
| 18443 | continue; |
| 18444 | } |
| 18445 | |
| 18446 | newactive = true; |
| 18447 | |
| 18448 | if (!dns_rdataset_isassociated(&keysigs)) { |
| 18449 | newalg = true; |
| 18450 | break; |
| 18451 | } |
| 18452 | |
| 18453 | if (signed_with_alg(&keysigs, dst_key_alg(key->key))) { |
| 18454 | /* |
| 18455 | * This isn't a new algorithm; clear |
| 18456 | * first_sign so we won't sign the |
| 18457 | * whole zone with this key later |
| 18458 | */ |
| 18459 | key->first_sign = false; |
| 18460 | } else { |
| 18461 | newalg = true; |
| 18462 | break; |
| 18463 | } |
| 18464 | } |
| 18465 | |
| 18466 | if ((newactive || fullsign || !ISC_LIST_EMPTY(diff.tuples)) && |
| 18467 | dnskey_sane(zone, db, ver, &diff)) |
| 18468 | { |
| 18469 | CHECK(dns_diff_apply(&diff, db, ver)); |
| 18470 | CHECK(clean_nsec3param(zone, db, ver, &diff)); |
| 18471 | CHECK(add_signing_records(db, zone->privatetype, |
| 18472 | ver, &diff, |
| 18473 | (newalg || fullsign))); |
| 18474 | CHECK(update_soa_serial(db, ver, &diff, mctx, |
| 18475 | zone->updatemethod)); |
| 18476 | CHECK(add_chains(zone, db, ver, &diff)); |
| 18477 | CHECK(sign_apex(zone, db, ver, now, &diff, &zonediff)); |
| 18478 | CHECK(zone_journal(zone, zonediff.diff, NULL, |
| 18479 | "zone_rekey" )); |
| 18480 | commit = true; |
| 18481 | } |
| 18482 | } |
| 18483 | |
| 18484 | dns_db_closeversion(db, &ver, true); |
| 18485 | |
| 18486 | if (commit) { |
| 18487 | dns_difftuple_t *tuple; |
| 18488 | |
| 18489 | LOCK_ZONE(zone); |
| 18490 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); |
| 18491 | |
| 18492 | zone_needdump(zone, DNS_DUMP_DELAY); |
| 18493 | |
| 18494 | zone_settimer(zone, &timenow); |
| 18495 | |
| 18496 | /* Remove any signatures from removed keys. */ |
| 18497 | if (!ISC_LIST_EMPTY(rmkeys)) { |
| 18498 | for (key = ISC_LIST_HEAD(rmkeys); |
| 18499 | key != NULL; |
| 18500 | key = ISC_LIST_NEXT(key, link)) |
| 18501 | { |
| 18502 | result = zone_signwithkey(zone, |
| 18503 | dst_key_alg(key->key), |
| 18504 | dst_key_id(key->key), |
| 18505 | true); |
| 18506 | if (result != ISC_R_SUCCESS) { |
| 18507 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18508 | "zone_signwithkey failed: %s" , |
| 18509 | dns_result_totext(result)); |
| 18510 | } |
| 18511 | } |
| 18512 | } |
| 18513 | |
| 18514 | if (fullsign) { |
| 18515 | /* |
| 18516 | * "rndc sign" was called, so we now sign the zone |
| 18517 | * with all active keys, whether they're new or not. |
| 18518 | */ |
| 18519 | for (key = ISC_LIST_HEAD(dnskeys); |
| 18520 | key != NULL; |
| 18521 | key = ISC_LIST_NEXT(key, link)) |
| 18522 | { |
| 18523 | if (!key->force_sign && !key->hint_sign) { |
| 18524 | continue; |
| 18525 | } |
| 18526 | |
| 18527 | result = zone_signwithkey(zone, |
| 18528 | dst_key_alg(key->key), |
| 18529 | dst_key_id(key->key), |
| 18530 | false); |
| 18531 | if (result != ISC_R_SUCCESS) { |
| 18532 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18533 | "zone_signwithkey failed: %s" , |
| 18534 | dns_result_totext(result)); |
| 18535 | } |
| 18536 | } |
| 18537 | } else if (newalg) { |
| 18538 | /* |
| 18539 | * We haven't been told to sign fully, but a new |
| 18540 | * algorithm was added to the DNSKEY. We sign |
| 18541 | * the full zone, but only with newly active |
| 18542 | * keys. |
| 18543 | */ |
| 18544 | for (key = ISC_LIST_HEAD(dnskeys); |
| 18545 | key != NULL; |
| 18546 | key = ISC_LIST_NEXT(key, link)) |
| 18547 | { |
| 18548 | if (!key->first_sign) { |
| 18549 | continue; |
| 18550 | } |
| 18551 | |
| 18552 | result = zone_signwithkey(zone, |
| 18553 | dst_key_alg(key->key), |
| 18554 | dst_key_id(key->key), |
| 18555 | false); |
| 18556 | if (result != ISC_R_SUCCESS) { |
| 18557 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18558 | "zone_signwithkey failed: %s" , |
| 18559 | dns_result_totext(result)); |
| 18560 | } |
| 18561 | } |
| 18562 | } |
| 18563 | |
| 18564 | /* |
| 18565 | * Clear fullsign flag, if it was set, so we don't do |
| 18566 | * another full signing next time |
| 18567 | */ |
| 18568 | zone->keyopts &= ~DNS_ZONEKEY_FULLSIGN; |
| 18569 | |
| 18570 | /* |
| 18571 | * Cause the zone to add/delete NSEC3 chains for the |
| 18572 | * deferred NSEC3PARAM changes. |
| 18573 | */ |
| 18574 | for (tuple = ISC_LIST_HEAD(zonediff.diff->tuples); |
| 18575 | tuple != NULL; |
| 18576 | tuple = ISC_LIST_NEXT(tuple, link)) |
| 18577 | { |
| 18578 | unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; |
| 18579 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 18580 | dns_rdata_nsec3param_t nsec3param; |
| 18581 | |
| 18582 | if (tuple->rdata.type != zone->privatetype || |
| 18583 | tuple->op != DNS_DIFFOP_ADD) |
| 18584 | { |
| 18585 | continue; |
| 18586 | } |
| 18587 | |
| 18588 | if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata, |
| 18589 | buf, sizeof(buf))) |
| 18590 | { |
| 18591 | continue; |
| 18592 | } |
| 18593 | |
| 18594 | result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); |
| 18595 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
| 18596 | if (nsec3param.flags == 0) { |
| 18597 | continue; |
| 18598 | } |
| 18599 | |
| 18600 | result = zone_addnsec3chain(zone, &nsec3param); |
| 18601 | if (result != ISC_R_SUCCESS) { |
| 18602 | dnssec_log(zone, ISC_LOG_ERROR, |
| 18603 | "zone_addnsec3chain failed: %s" , |
| 18604 | dns_result_totext(result)); |
| 18605 | } |
| 18606 | } |
| 18607 | |
| 18608 | /* |
| 18609 | * Activate any NSEC3 chain updates that may have |
| 18610 | * been scheduled before this rekey. |
| 18611 | */ |
| 18612 | if (fullsign || newalg) { |
| 18613 | resume_addnsec3chain(zone); |
| 18614 | } |
| 18615 | |
| 18616 | /* |
| 18617 | * Schedule the next resigning event |
| 18618 | */ |
| 18619 | set_resigntime(zone); |
| 18620 | UNLOCK_ZONE(zone); |
| 18621 | } |
| 18622 | |
| 18623 | isc_time_settoepoch(&zone->refreshkeytime); |
| 18624 | |
| 18625 | /* |
| 18626 | * If we're doing key maintenance, set the key refresh timer to |
| 18627 | * the next scheduled key event or to 'dnssec-loadkeys-interval' |
| 18628 | * seconds in the future, whichever is sooner. |
| 18629 | */ |
| 18630 | if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) { |
| 18631 | isc_time_t timethen; |
| 18632 | isc_stdtime_t then; |
| 18633 | |
| 18634 | LOCK_ZONE(zone); |
| 18635 | DNS_ZONE_TIME_ADD(&timenow, zone->refreshkeyinterval, |
| 18636 | &timethen); |
| 18637 | zone->refreshkeytime = timethen; |
| 18638 | UNLOCK_ZONE(zone); |
| 18639 | |
| 18640 | for (key = ISC_LIST_HEAD(dnskeys); |
| 18641 | key != NULL; |
| 18642 | key = ISC_LIST_NEXT(key, link)) |
| 18643 | { |
| 18644 | then = now; |
| 18645 | result = next_keyevent(key->key, &then); |
| 18646 | if (result != ISC_R_SUCCESS) { |
| 18647 | continue; |
| 18648 | } |
| 18649 | |
| 18650 | DNS_ZONE_TIME_ADD(&timenow, then - now, &timethen); |
| 18651 | LOCK_ZONE(zone); |
| 18652 | if (isc_time_compare(&timethen, |
| 18653 | &zone->refreshkeytime) < 0) |
| 18654 | { |
| 18655 | zone->refreshkeytime = timethen; |
| 18656 | } |
| 18657 | UNLOCK_ZONE(zone); |
| 18658 | } |
| 18659 | |
| 18660 | zone_settimer(zone, &timenow); |
| 18661 | |
| 18662 | isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80); |
| 18663 | dnssec_log(zone, ISC_LOG_INFO, "next key event: %s" , timebuf); |
| 18664 | } |
| 18665 | |
| 18666 | result = ISC_R_SUCCESS; |
| 18667 | |
| 18668 | failure: |
| 18669 | if (result != ISC_R_SUCCESS) { |
| 18670 | /* |
| 18671 | * Something went wrong; try again in ten minutes or |
| 18672 | * after a key refresh interval, whichever is shorter. |
| 18673 | */ |
| 18674 | isc_interval_set(&ival, |
| 18675 | ISC_MIN(zone->refreshkeyinterval, 600), 0); |
| 18676 | isc_time_nowplusinterval(&zone->refreshkeytime, &ival); |
| 18677 | } |
| 18678 | |
| 18679 | dns_diff_clear(&diff); |
| 18680 | dns_diff_clear(&_sig_diff); |
| 18681 | |
| 18682 | clear_keylist(&dnskeys, mctx); |
| 18683 | clear_keylist(&keys, mctx); |
| 18684 | clear_keylist(&rmkeys, mctx); |
| 18685 | |
| 18686 | if (ver != NULL) { |
| 18687 | dns_db_closeversion(db, &ver, false); |
| 18688 | } |
| 18689 | if (dns_rdataset_isassociated(&cdsset)) { |
| 18690 | dns_rdataset_disassociate(&cdsset); |
| 18691 | } |
| 18692 | if (dns_rdataset_isassociated(&keyset)) { |
| 18693 | dns_rdataset_disassociate(&keyset); |
| 18694 | } |
| 18695 | if (dns_rdataset_isassociated(&keysigs)) { |
| 18696 | dns_rdataset_disassociate(&keysigs); |
| 18697 | } |
| 18698 | if (dns_rdataset_isassociated(&soasigs)) { |
| 18699 | dns_rdataset_disassociate(&soasigs); |
| 18700 | } |
| 18701 | if (dns_rdataset_isassociated(&cdnskeyset)) { |
| 18702 | dns_rdataset_disassociate(&cdnskeyset); |
| 18703 | } |
| 18704 | if (node != NULL) { |
| 18705 | dns_db_detachnode(db, &node); |
| 18706 | } |
| 18707 | if (db != NULL) { |
| 18708 | dns_db_detach(&db); |
| 18709 | } |
| 18710 | |
| 18711 | INSIST(ver == NULL); |
| 18712 | } |
| 18713 | |
| 18714 | void |
| 18715 | dns_zone_rekey(dns_zone_t *zone, bool fullsign) { |
| 18716 | isc_time_t now; |
| 18717 | |
| 18718 | if (zone->type == dns_zone_master && zone->task != NULL) { |
| 18719 | LOCK_ZONE(zone); |
| 18720 | |
| 18721 | if (fullsign) |
| 18722 | zone->keyopts |= DNS_ZONEKEY_FULLSIGN; |
| 18723 | |
| 18724 | TIME_NOW(&now); |
| 18725 | zone->refreshkeytime = now; |
| 18726 | zone_settimer(zone, &now); |
| 18727 | |
| 18728 | UNLOCK_ZONE(zone); |
| 18729 | } |
| 18730 | } |
| 18731 | |
| 18732 | isc_result_t |
| 18733 | dns_zone_nscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, |
| 18734 | unsigned int *errors) |
| 18735 | { |
| 18736 | isc_result_t result; |
| 18737 | dns_dbnode_t *node = NULL; |
| 18738 | |
| 18739 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18740 | REQUIRE(errors != NULL); |
| 18741 | |
| 18742 | result = dns_db_getoriginnode(db, &node); |
| 18743 | if (result != ISC_R_SUCCESS) |
| 18744 | return (result); |
| 18745 | result = zone_count_ns_rr(zone, db, node, version, NULL, errors, |
| 18746 | false); |
| 18747 | dns_db_detachnode(db, &node); |
| 18748 | return (result); |
| 18749 | } |
| 18750 | |
| 18751 | isc_result_t |
| 18752 | dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) { |
| 18753 | isc_result_t result; |
| 18754 | dns_dbnode_t *node = NULL; |
| 18755 | dns_rdataset_t dnskey, cds, cdnskey; |
| 18756 | unsigned char buffer[DNS_DS_BUFFERSIZE]; |
| 18757 | unsigned char algorithms[256]; |
| 18758 | unsigned int i; |
| 18759 | |
| 18760 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18761 | |
| 18762 | result = dns_db_getoriginnode(db, &node); |
| 18763 | if (result != ISC_R_SUCCESS) |
| 18764 | return (result); |
| 18765 | |
| 18766 | dns_rdataset_init(&cds); |
| 18767 | dns_rdataset_init(&dnskey); |
| 18768 | dns_rdataset_init(&cdnskey); |
| 18769 | |
| 18770 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_cds, |
| 18771 | dns_rdatatype_none, 0, &cds, NULL); |
| 18772 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) |
| 18773 | goto failure; |
| 18774 | |
| 18775 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_cdnskey, |
| 18776 | dns_rdatatype_none, 0, &cdnskey, NULL); |
| 18777 | if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) |
| 18778 | goto failure; |
| 18779 | |
| 18780 | if (!dns_rdataset_isassociated(&cds) && |
| 18781 | !dns_rdataset_isassociated(&cdnskey)) { |
| 18782 | result = ISC_R_SUCCESS; |
| 18783 | goto failure; |
| 18784 | } |
| 18785 | |
| 18786 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, |
| 18787 | dns_rdatatype_none, 0, &dnskey, NULL); |
| 18788 | if (result == ISC_R_NOTFOUND) { |
| 18789 | if (dns_rdataset_isassociated(&cds)) |
| 18790 | result = DNS_R_BADCDS; |
| 18791 | else |
| 18792 | result = DNS_R_BADCDNSKEY; |
| 18793 | goto failure; |
| 18794 | } |
| 18795 | if (result != ISC_R_SUCCESS) |
| 18796 | goto failure; |
| 18797 | |
| 18798 | /* |
| 18799 | * For each DNSSEC algorithm in the CDS RRset there must be |
| 18800 | * a matching DNSKEY record. |
| 18801 | */ |
| 18802 | if (dns_rdataset_isassociated(&cds)) { |
| 18803 | memset(algorithms, 0, sizeof(algorithms)); |
| 18804 | for (result = dns_rdataset_first(&cds); |
| 18805 | result == ISC_R_SUCCESS; |
| 18806 | result = dns_rdataset_next(&cds)) { |
| 18807 | dns_rdata_t crdata = DNS_RDATA_INIT; |
| 18808 | dns_rdata_cds_t structcds; |
| 18809 | |
| 18810 | dns_rdataset_current(&cds, &crdata); |
| 18811 | CHECK(dns_rdata_tostruct(&crdata, &structcds, NULL)); |
| 18812 | if (algorithms[structcds.algorithm] == 0) |
| 18813 | algorithms[structcds.algorithm] = 1; |
| 18814 | for (result = dns_rdataset_first(&dnskey); |
| 18815 | result == ISC_R_SUCCESS; |
| 18816 | result = dns_rdataset_next(&dnskey)) { |
| 18817 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 18818 | dns_rdata_t dsrdata = DNS_RDATA_INIT; |
| 18819 | |
| 18820 | dns_rdataset_current(&dnskey, &rdata); |
| 18821 | CHECK(dns_ds_buildrdata(&zone->origin, &rdata, |
| 18822 | structcds.digest_type, |
| 18823 | buffer, &dsrdata)); |
| 18824 | if (crdata.length == dsrdata.length && |
| 18825 | memcmp(crdata.data, dsrdata.data, |
| 18826 | dsrdata.length) == 0) { |
| 18827 | algorithms[structcds.algorithm] = 2; |
| 18828 | } |
| 18829 | } |
| 18830 | if (result != ISC_R_NOMORE) |
| 18831 | goto failure; |
| 18832 | } |
| 18833 | for (i = 0; i < sizeof(algorithms); i++) { |
| 18834 | if (algorithms[i] == 1) { |
| 18835 | result = DNS_R_BADCDNSKEY; |
| 18836 | goto failure; |
| 18837 | } |
| 18838 | } |
| 18839 | } |
| 18840 | |
| 18841 | /* |
| 18842 | * For each DNSSEC algorithm in the CDNSKEY RRset there must be |
| 18843 | * a matching DNSKEY record. |
| 18844 | */ |
| 18845 | if (dns_rdataset_isassociated(&cdnskey)) { |
| 18846 | memset(algorithms, 0, sizeof(algorithms)); |
| 18847 | for (result = dns_rdataset_first(&cdnskey); |
| 18848 | result == ISC_R_SUCCESS; |
| 18849 | result = dns_rdataset_next(&cdnskey)) { |
| 18850 | dns_rdata_t crdata = DNS_RDATA_INIT; |
| 18851 | dns_rdata_cdnskey_t structcdnskey; |
| 18852 | |
| 18853 | dns_rdataset_current(&cdnskey, &crdata); |
| 18854 | CHECK(dns_rdata_tostruct(&crdata, &structcdnskey, |
| 18855 | NULL)); |
| 18856 | if (algorithms[structcdnskey.algorithm] == 0) |
| 18857 | algorithms[structcdnskey.algorithm] = 1; |
| 18858 | for (result = dns_rdataset_first(&dnskey); |
| 18859 | result == ISC_R_SUCCESS; |
| 18860 | result = dns_rdataset_next(&dnskey)) { |
| 18861 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 18862 | |
| 18863 | dns_rdataset_current(&dnskey, &rdata); |
| 18864 | if (crdata.length == rdata.length && |
| 18865 | memcmp(crdata.data, rdata.data, |
| 18866 | rdata.length) == 0) { |
| 18867 | algorithms[structcdnskey.algorithm] = 2; |
| 18868 | } |
| 18869 | } |
| 18870 | if (result != ISC_R_NOMORE) |
| 18871 | goto failure; |
| 18872 | } |
| 18873 | for (i = 0; i < sizeof(algorithms); i++) { |
| 18874 | if (algorithms[i] == 1) { |
| 18875 | result = DNS_R_BADCDS; |
| 18876 | goto failure; |
| 18877 | } |
| 18878 | } |
| 18879 | } |
| 18880 | result = ISC_R_SUCCESS; |
| 18881 | |
| 18882 | failure: |
| 18883 | if (dns_rdataset_isassociated(&cds)) |
| 18884 | dns_rdataset_disassociate(&cds); |
| 18885 | if (dns_rdataset_isassociated(&dnskey)) |
| 18886 | dns_rdataset_disassociate(&dnskey); |
| 18887 | if (dns_rdataset_isassociated(&cdnskey)) |
| 18888 | dns_rdataset_disassociate(&cdnskey); |
| 18889 | dns_db_detachnode(db, &node); |
| 18890 | return (result); |
| 18891 | } |
| 18892 | |
| 18893 | void |
| 18894 | dns_zone_setautomatic(dns_zone_t *zone, bool automatic) { |
| 18895 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18896 | |
| 18897 | LOCK_ZONE(zone); |
| 18898 | zone->automatic = automatic; |
| 18899 | UNLOCK_ZONE(zone); |
| 18900 | } |
| 18901 | |
| 18902 | bool |
| 18903 | dns_zone_getautomatic(dns_zone_t *zone) { |
| 18904 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18905 | return (zone->automatic); |
| 18906 | } |
| 18907 | |
| 18908 | void |
| 18909 | dns_zone_setadded(dns_zone_t *zone, bool added) { |
| 18910 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18911 | |
| 18912 | LOCK_ZONE(zone); |
| 18913 | zone->added = added; |
| 18914 | UNLOCK_ZONE(zone); |
| 18915 | } |
| 18916 | |
| 18917 | bool |
| 18918 | dns_zone_getadded(dns_zone_t *zone) { |
| 18919 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18920 | return (zone->added); |
| 18921 | } |
| 18922 | |
| 18923 | isc_result_t |
| 18924 | dns_zone_dlzpostload(dns_zone_t *zone, dns_db_t *db) |
| 18925 | { |
| 18926 | isc_time_t loadtime; |
| 18927 | isc_result_t result; |
| 18928 | dns_zone_t *secure = NULL; |
| 18929 | |
| 18930 | TIME_NOW(&loadtime); |
| 18931 | |
| 18932 | /* |
| 18933 | * Lock hierarchy: zmgr, zone, raw. |
| 18934 | */ |
| 18935 | again: |
| 18936 | LOCK_ZONE(zone); |
| 18937 | INSIST(zone != zone->raw); |
| 18938 | if (inline_secure(zone)) |
| 18939 | LOCK_ZONE(zone->raw); |
| 18940 | else if (inline_raw(zone)) { |
| 18941 | secure = zone->secure; |
| 18942 | TRYLOCK_ZONE(result, secure); |
| 18943 | if (result != ISC_R_SUCCESS) { |
| 18944 | UNLOCK_ZONE(zone); |
| 18945 | secure = NULL; |
| 18946 | isc_thread_yield(); |
| 18947 | goto again; |
| 18948 | } |
| 18949 | } |
| 18950 | result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS); |
| 18951 | if (inline_secure(zone)) |
| 18952 | UNLOCK_ZONE(zone->raw); |
| 18953 | else if (secure != NULL) |
| 18954 | UNLOCK_ZONE(secure); |
| 18955 | UNLOCK_ZONE(zone); |
| 18956 | return result; |
| 18957 | } |
| 18958 | |
| 18959 | isc_result_t |
| 18960 | dns_zone_setrefreshkeyinterval(dns_zone_t *zone, uint32_t interval) { |
| 18961 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18962 | if (interval == 0) |
| 18963 | return (ISC_R_RANGE); |
| 18964 | /* Maximum value: 24 hours (3600 minutes) */ |
| 18965 | if (interval > (24 * 60)) |
| 18966 | interval = (24 * 60); |
| 18967 | /* Multiply by 60 for seconds */ |
| 18968 | zone->refreshkeyinterval = interval * 60; |
| 18969 | return (ISC_R_SUCCESS); |
| 18970 | } |
| 18971 | |
| 18972 | void |
| 18973 | dns_zone_setrequestixfr(dns_zone_t *zone, bool flag) { |
| 18974 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18975 | zone->requestixfr = flag; |
| 18976 | } |
| 18977 | |
| 18978 | bool |
| 18979 | dns_zone_getrequestixfr(dns_zone_t *zone) { |
| 18980 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18981 | return (zone->requestixfr); |
| 18982 | } |
| 18983 | |
| 18984 | void |
| 18985 | dns_zone_setrequestexpire(dns_zone_t *zone, bool flag) { |
| 18986 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18987 | zone->requestexpire = flag; |
| 18988 | } |
| 18989 | |
| 18990 | bool |
| 18991 | dns_zone_getrequestexpire(dns_zone_t *zone) { |
| 18992 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18993 | return (zone->requestexpire); |
| 18994 | } |
| 18995 | |
| 18996 | void |
| 18997 | dns_zone_setserialupdatemethod(dns_zone_t *zone, dns_updatemethod_t method) { |
| 18998 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 18999 | zone->updatemethod = method; |
| 19000 | } |
| 19001 | |
| 19002 | dns_updatemethod_t |
| 19003 | dns_zone_getserialupdatemethod(dns_zone_t *zone) { |
| 19004 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19005 | return(zone->updatemethod); |
| 19006 | } |
| 19007 | |
| 19008 | /* |
| 19009 | * Lock hierarchy: zmgr, zone, raw. |
| 19010 | */ |
| 19011 | isc_result_t |
| 19012 | dns_zone_link(dns_zone_t *zone, dns_zone_t *raw) { |
| 19013 | isc_result_t result; |
| 19014 | dns_zonemgr_t *zmgr; |
| 19015 | |
| 19016 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19017 | REQUIRE(zone->zmgr != NULL); |
| 19018 | REQUIRE(zone->task != NULL); |
| 19019 | REQUIRE(zone->loadtask != NULL); |
| 19020 | REQUIRE(zone->raw == NULL); |
| 19021 | |
| 19022 | REQUIRE(DNS_ZONE_VALID(raw)); |
| 19023 | REQUIRE(raw->zmgr == NULL); |
| 19024 | REQUIRE(raw->task == NULL); |
| 19025 | REQUIRE(raw->loadtask == NULL); |
| 19026 | REQUIRE(raw->secure == NULL); |
| 19027 | |
| 19028 | REQUIRE(zone != raw); |
| 19029 | |
| 19030 | /* |
| 19031 | * Lock hierarchy: zmgr, zone, raw. |
| 19032 | */ |
| 19033 | zmgr = zone->zmgr; |
| 19034 | RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 19035 | LOCK_ZONE(zone); |
| 19036 | LOCK_ZONE(raw); |
| 19037 | |
| 19038 | result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive, |
| 19039 | NULL, NULL, zone->task, zone_timer, raw, |
| 19040 | &raw->timer); |
| 19041 | if (result != ISC_R_SUCCESS) |
| 19042 | goto unlock; |
| 19043 | |
| 19044 | /* |
| 19045 | * The timer "holds" a iref. |
| 19046 | */ |
| 19047 | raw->irefs++; |
| 19048 | INSIST(raw->irefs != 0); |
| 19049 | |
| 19050 | |
| 19051 | /* dns_zone_attach(raw, &zone->raw); */ |
| 19052 | isc_refcount_increment(&raw->erefs); |
| 19053 | zone->raw = raw; |
| 19054 | |
| 19055 | /* dns_zone_iattach(zone, &raw->secure); */ |
| 19056 | zone_iattach(zone, &raw->secure); |
| 19057 | |
| 19058 | isc_task_attach(zone->task, &raw->task); |
| 19059 | isc_task_attach(zone->loadtask, &raw->loadtask); |
| 19060 | |
| 19061 | ISC_LIST_APPEND(zmgr->zones, raw, link); |
| 19062 | raw->zmgr = zmgr; |
| 19063 | zmgr->refs++; |
| 19064 | |
| 19065 | unlock: |
| 19066 | UNLOCK_ZONE(raw); |
| 19067 | UNLOCK_ZONE(zone); |
| 19068 | RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); |
| 19069 | return (result); |
| 19070 | } |
| 19071 | |
| 19072 | void |
| 19073 | dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw) { |
| 19074 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19075 | REQUIRE(raw != NULL && *raw == NULL); |
| 19076 | |
| 19077 | LOCK(&zone->lock); |
| 19078 | INSIST(zone != zone->raw); |
| 19079 | if (zone->raw != NULL) |
| 19080 | dns_zone_attach(zone->raw, raw); |
| 19081 | UNLOCK(&zone->lock); |
| 19082 | } |
| 19083 | |
| 19084 | struct keydone { |
| 19085 | isc_event_t event; |
| 19086 | bool all; |
| 19087 | unsigned char data[5]; |
| 19088 | }; |
| 19089 | |
| 19090 | #define PENDINGFLAGS (DNS_NSEC3FLAG_CREATE|DNS_NSEC3FLAG_INITIAL) |
| 19091 | |
| 19092 | static void |
| 19093 | keydone(isc_task_t *task, isc_event_t *event) { |
| 19094 | const char *me = "keydone" ; |
| 19095 | bool commit = false; |
| 19096 | isc_result_t result; |
| 19097 | dns_rdata_t rdata = DNS_RDATA_INIT; |
| 19098 | dns_dbversion_t *oldver = NULL, *newver = NULL; |
| 19099 | dns_zone_t *zone; |
| 19100 | dns_db_t *db = NULL; |
| 19101 | dns_dbnode_t *node = NULL; |
| 19102 | dns_rdataset_t rdataset; |
| 19103 | dns_diff_t diff; |
| 19104 | struct keydone *kd = (struct keydone *)event; |
| 19105 | dns_update_log_t log = { update_log_cb, NULL }; |
| 19106 | bool clear_pending = false; |
| 19107 | |
| 19108 | UNUSED(task); |
| 19109 | |
| 19110 | zone = event->ev_arg; |
| 19111 | INSIST(DNS_ZONE_VALID(zone)); |
| 19112 | |
| 19113 | ENTER; |
| 19114 | |
| 19115 | dns_rdataset_init(&rdataset); |
| 19116 | dns_diff_init(zone->mctx, &diff); |
| 19117 | |
| 19118 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 19119 | if (zone->db != NULL) { |
| 19120 | dns_db_attach(zone->db, &db); |
| 19121 | } |
| 19122 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 19123 | if (db == NULL) { |
| 19124 | goto failure; |
| 19125 | } |
| 19126 | |
| 19127 | dns_db_currentversion(db, &oldver); |
| 19128 | result = dns_db_newversion(db, &newver); |
| 19129 | if (result != ISC_R_SUCCESS) { |
| 19130 | dnssec_log(zone, ISC_LOG_ERROR, |
| 19131 | "keydone:dns_db_newversion -> %s" , |
| 19132 | dns_result_totext(result)); |
| 19133 | goto failure; |
| 19134 | } |
| 19135 | |
| 19136 | result = dns_db_getoriginnode(db, &node); |
| 19137 | if (result != ISC_R_SUCCESS) { |
| 19138 | goto failure; |
| 19139 | } |
| 19140 | |
| 19141 | result = dns_db_findrdataset(db, node, newver, zone->privatetype, |
| 19142 | dns_rdatatype_none, 0, &rdataset, NULL); |
| 19143 | if (result == ISC_R_NOTFOUND) { |
| 19144 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 19145 | goto failure; |
| 19146 | } |
| 19147 | if (result != ISC_R_SUCCESS) { |
| 19148 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
| 19149 | goto failure; |
| 19150 | } |
| 19151 | |
| 19152 | for (result = dns_rdataset_first(&rdataset); |
| 19153 | result == ISC_R_SUCCESS; |
| 19154 | result = dns_rdataset_next(&rdataset)) |
| 19155 | { |
| 19156 | bool found = false; |
| 19157 | |
| 19158 | dns_rdataset_current(&rdataset, &rdata); |
| 19159 | |
| 19160 | if (kd->all) { |
| 19161 | if (rdata.length == 5 && rdata.data[0] != 0 && |
| 19162 | rdata.data[3] == 0 && rdata.data[4] == 1) |
| 19163 | { |
| 19164 | found = true; |
| 19165 | } else if (rdata.data[0] == 0 && |
| 19166 | (rdata.data[2] & PENDINGFLAGS) != 0) |
| 19167 | { |
| 19168 | found = true; |
| 19169 | clear_pending = true; |
| 19170 | } |
| 19171 | } else if (rdata.length == 5 && |
| 19172 | memcmp(rdata.data, kd->data, 5) == 0) |
| 19173 | { |
| 19174 | found = true; |
| 19175 | } |
| 19176 | |
| 19177 | if (found) { |
| 19178 | CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_DEL, |
| 19179 | &zone->origin, rdataset.ttl, |
| 19180 | &rdata)); |
| 19181 | } |
| 19182 | dns_rdata_reset(&rdata); |
| 19183 | } |
| 19184 | |
| 19185 | if (!ISC_LIST_EMPTY(diff.tuples)) { |
| 19186 | /* Write changes to journal file. */ |
| 19187 | CHECK(update_soa_serial(db, newver, &diff, zone->mctx, |
| 19188 | zone->updatemethod)); |
| 19189 | |
| 19190 | result = dns_update_signatures(&log, zone, db, |
| 19191 | oldver, newver, &diff, |
| 19192 | zone->sigvalidityinterval); |
| 19193 | if (!clear_pending) { |
| 19194 | CHECK(result); |
| 19195 | } |
| 19196 | |
| 19197 | CHECK(zone_journal(zone, &diff, NULL, "keydone" )); |
| 19198 | commit = true; |
| 19199 | |
| 19200 | LOCK_ZONE(zone); |
| 19201 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); |
| 19202 | zone_needdump(zone, 30); |
| 19203 | UNLOCK_ZONE(zone); |
| 19204 | } |
| 19205 | |
| 19206 | failure: |
| 19207 | if (dns_rdataset_isassociated(&rdataset)) { |
| 19208 | dns_rdataset_disassociate(&rdataset); |
| 19209 | } |
| 19210 | if (db != NULL) { |
| 19211 | if (node != NULL) { |
| 19212 | dns_db_detachnode(db, &node); |
| 19213 | } |
| 19214 | if (oldver != NULL) { |
| 19215 | dns_db_closeversion(db, &oldver, false); |
| 19216 | } |
| 19217 | if (newver != NULL) { |
| 19218 | dns_db_closeversion(db, &newver, commit); |
| 19219 | } |
| 19220 | dns_db_detach(&db); |
| 19221 | } |
| 19222 | dns_diff_clear(&diff); |
| 19223 | isc_event_free(&event); |
| 19224 | dns_zone_idetach(&zone); |
| 19225 | |
| 19226 | INSIST(oldver == NULL); |
| 19227 | INSIST(newver == NULL); |
| 19228 | } |
| 19229 | |
| 19230 | isc_result_t |
| 19231 | dns_zone_keydone(dns_zone_t *zone, const char *keystr) { |
| 19232 | isc_result_t result = ISC_R_SUCCESS; |
| 19233 | isc_event_t *e; |
| 19234 | isc_buffer_t b; |
| 19235 | dns_zone_t *dummy = NULL; |
| 19236 | struct keydone *kd; |
| 19237 | |
| 19238 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19239 | |
| 19240 | LOCK_ZONE(zone); |
| 19241 | |
| 19242 | e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_KEYDONE, keydone, |
| 19243 | zone, sizeof(struct keydone)); |
| 19244 | if (e == NULL) { |
| 19245 | result = ISC_R_NOMEMORY; |
| 19246 | goto failure; |
| 19247 | } |
| 19248 | |
| 19249 | kd = (struct keydone *) e; |
| 19250 | if (strcasecmp(keystr, "all" ) == 0) { |
| 19251 | kd->all = true; |
| 19252 | } else { |
| 19253 | isc_textregion_t r; |
| 19254 | const char *algstr; |
| 19255 | dns_keytag_t keyid; |
| 19256 | dns_secalg_t alg; |
| 19257 | size_t n; |
| 19258 | |
| 19259 | kd->all = false; |
| 19260 | |
| 19261 | n = sscanf(keystr, "%hu/" , &keyid); |
| 19262 | if (n == 0U) { |
| 19263 | CHECK(ISC_R_FAILURE); |
| 19264 | } |
| 19265 | |
| 19266 | algstr = strchr(keystr, '/'); |
| 19267 | if (algstr != NULL) { |
| 19268 | algstr++; |
| 19269 | } else { |
| 19270 | CHECK(ISC_R_FAILURE); |
| 19271 | } |
| 19272 | |
| 19273 | n = sscanf(algstr, "%hhu" , &alg); |
| 19274 | if (n == 0U) { |
| 19275 | DE_CONST(algstr, r.base); |
| 19276 | r.length = strlen(algstr); |
| 19277 | CHECK(dns_secalg_fromtext(&alg, &r)); |
| 19278 | } |
| 19279 | |
| 19280 | /* construct a private-type rdata */ |
| 19281 | isc_buffer_init(&b, kd->data, sizeof(kd->data)); |
| 19282 | isc_buffer_putuint8(&b, alg); |
| 19283 | isc_buffer_putuint8(&b, (keyid & 0xff00) >> 8); |
| 19284 | isc_buffer_putuint8(&b, (keyid & 0xff)); |
| 19285 | isc_buffer_putuint8(&b, 0); |
| 19286 | isc_buffer_putuint8(&b, 1); |
| 19287 | } |
| 19288 | |
| 19289 | zone_iattach(zone, &dummy); |
| 19290 | isc_task_send(zone->task, &e); |
| 19291 | |
| 19292 | failure: |
| 19293 | if (e != NULL) { |
| 19294 | isc_event_free(&e); |
| 19295 | } |
| 19296 | UNLOCK_ZONE(zone); |
| 19297 | return (result); |
| 19298 | } |
| 19299 | |
| 19300 | /* |
| 19301 | * Called from the zone task's queue after the relevant event is posted by |
| 19302 | * dns_zone_setnsec3param(). |
| 19303 | * |
| 19304 | * Check whether NSEC3 chain addition or removal specified by the private-type |
| 19305 | * record passed with the event was already queued (or even fully performed). |
| 19306 | * If not, modify the relevant private-type records at the zone apex and call |
| 19307 | * resume_addnsec3chain(). |
| 19308 | */ |
| 19309 | static void |
| 19310 | setnsec3param(isc_task_t *task, isc_event_t *event) { |
| 19311 | const char *me = "setnsec3param" ; |
| 19312 | bool commit = false; |
| 19313 | isc_result_t result; |
| 19314 | dns_dbversion_t *oldver = NULL, *newver = NULL; |
| 19315 | dns_zone_t *zone; |
| 19316 | dns_db_t *db = NULL; |
| 19317 | dns_dbnode_t *node = NULL; |
| 19318 | dns_rdataset_t prdataset, nrdataset; |
| 19319 | dns_diff_t diff; |
| 19320 | struct np3event *npe = (struct np3event *)event; |
| 19321 | nsec3param_t *np; |
| 19322 | dns_update_log_t log = { update_log_cb, NULL }; |
| 19323 | dns_rdata_t rdata; |
| 19324 | bool nseconly; |
| 19325 | bool exists = false; |
| 19326 | |
| 19327 | UNUSED(task); |
| 19328 | |
| 19329 | zone = event->ev_arg; |
| 19330 | INSIST(DNS_ZONE_VALID(zone)); |
| 19331 | |
| 19332 | ENTER; |
| 19333 | |
| 19334 | np = &npe->params; |
| 19335 | |
| 19336 | dns_rdataset_init(&prdataset); |
| 19337 | dns_rdataset_init(&nrdataset); |
| 19338 | dns_diff_init(zone->mctx, &diff); |
| 19339 | |
| 19340 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 19341 | if (zone->db != NULL) { |
| 19342 | dns_db_attach(zone->db, &db); |
| 19343 | } |
| 19344 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 19345 | if (db == NULL) { |
| 19346 | goto failure; |
| 19347 | } |
| 19348 | |
| 19349 | dns_db_currentversion(db, &oldver); |
| 19350 | result = dns_db_newversion(db, &newver); |
| 19351 | if (result != ISC_R_SUCCESS) { |
| 19352 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 19353 | dnssec_log(zone, ISC_LOG_ERROR, |
| 19354 | "setnsec3param:dns_db_newversion -> %s" , |
| 19355 | dns_result_totext(result)); |
| 19356 | goto failure; |
| 19357 | } |
| 19358 | |
| 19359 | CHECK(dns_db_getoriginnode(db, &node)); |
| 19360 | |
| 19361 | /* |
| 19362 | * Does a private-type record already exist for this chain? |
| 19363 | */ |
| 19364 | result = dns_db_findrdataset(db, node, newver, zone->privatetype, |
| 19365 | dns_rdatatype_none, 0, &prdataset, NULL); |
| 19366 | if (result == ISC_R_SUCCESS) { |
| 19367 | for (result = dns_rdataset_first(&prdataset); |
| 19368 | result == ISC_R_SUCCESS; |
| 19369 | result = dns_rdataset_next(&prdataset)) |
| 19370 | { |
| 19371 | dns_rdata_init(&rdata); |
| 19372 | dns_rdataset_current(&prdataset, &rdata); |
| 19373 | |
| 19374 | if (np->length == rdata.length && |
| 19375 | memcmp(rdata.data, np->data, np->length) == 0) |
| 19376 | { |
| 19377 | exists = true; |
| 19378 | break; |
| 19379 | } |
| 19380 | } |
| 19381 | } else if (result != ISC_R_NOTFOUND) { |
| 19382 | INSIST(!dns_rdataset_isassociated(&prdataset)); |
| 19383 | goto failure; |
| 19384 | } |
| 19385 | |
| 19386 | /* |
| 19387 | * Does the chain already exist? |
| 19388 | */ |
| 19389 | result = dns_db_findrdataset(db, node, newver, |
| 19390 | dns_rdatatype_nsec3param, |
| 19391 | dns_rdatatype_none, 0, &nrdataset, NULL); |
| 19392 | if (result == ISC_R_SUCCESS) { |
| 19393 | for (result = dns_rdataset_first(&nrdataset); |
| 19394 | result == ISC_R_SUCCESS; |
| 19395 | result = dns_rdataset_next(&nrdataset)) |
| 19396 | { |
| 19397 | dns_rdata_init(&rdata); |
| 19398 | dns_rdataset_current(&nrdataset, &rdata); |
| 19399 | |
| 19400 | if (np->length == (rdata.length + 1) && |
| 19401 | memcmp(rdata.data, np->data + 1, |
| 19402 | np->length - 1) == 0) |
| 19403 | { |
| 19404 | exists = true; |
| 19405 | break; |
| 19406 | } |
| 19407 | } |
| 19408 | } else if (result != ISC_R_NOTFOUND) { |
| 19409 | INSIST(!dns_rdataset_isassociated(&nrdataset)); |
| 19410 | goto failure; |
| 19411 | } |
| 19412 | |
| 19413 | |
| 19414 | /* |
| 19415 | * We need to remove any existing NSEC3 chains if the supplied NSEC3 |
| 19416 | * parameters are supposed to replace the current ones or if we are |
| 19417 | * switching to NSEC. |
| 19418 | */ |
| 19419 | if (!exists && np->replace && (np->length != 0 || np->nsec)) { |
| 19420 | CHECK(dns_nsec3param_deletechains(db, newver, zone, |
| 19421 | !np->nsec, &diff)); |
| 19422 | } |
| 19423 | |
| 19424 | if (!exists && np->length != 0) { |
| 19425 | /* |
| 19426 | * We're creating an NSEC3 chain. Add the private-type record |
| 19427 | * passed in the event handler's argument to the zone apex. |
| 19428 | * |
| 19429 | * If the zone is not currently capable of supporting an NSEC3 |
| 19430 | * chain (due to the DNSKEY RRset at the zone apex not existing |
| 19431 | * or containing at least one key using an NSEC-only |
| 19432 | * algorithm), add the INITIAL flag, so these parameters can be |
| 19433 | * used later when NSEC3 becomes available. |
| 19434 | */ |
| 19435 | dns_rdata_init(&rdata); |
| 19436 | |
| 19437 | np->data[2] |= DNS_NSEC3FLAG_CREATE; |
| 19438 | result = dns_nsec_nseconly(db, newver, &nseconly); |
| 19439 | if (result == ISC_R_NOTFOUND || nseconly) { |
| 19440 | np->data[2] |= DNS_NSEC3FLAG_INITIAL; |
| 19441 | } |
| 19442 | |
| 19443 | rdata.length = np->length; |
| 19444 | rdata.data = np->data; |
| 19445 | rdata.type = zone->privatetype; |
| 19446 | rdata.rdclass = zone->rdclass; |
| 19447 | CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_ADD, |
| 19448 | &zone->origin, 0, &rdata)); |
| 19449 | } |
| 19450 | |
| 19451 | /* |
| 19452 | * If we changed anything in the zone, write changes to journal file |
| 19453 | * and set commit to true so that resume_addnsec3chain() will be |
| 19454 | * called below in order to kick off adding/removing relevant NSEC3 |
| 19455 | * records. |
| 19456 | */ |
| 19457 | if (!ISC_LIST_EMPTY(diff.tuples)) { |
| 19458 | CHECK(update_soa_serial(db, newver, &diff, zone->mctx, |
| 19459 | zone->updatemethod)); |
| 19460 | result = dns_update_signatures(&log, zone, db, |
| 19461 | oldver, newver, &diff, |
| 19462 | zone->sigvalidityinterval); |
| 19463 | if (result != ISC_R_NOTFOUND) { |
| 19464 | CHECK(result); |
| 19465 | } |
| 19466 | CHECK(zone_journal(zone, &diff, NULL, "setnsec3param" )); |
| 19467 | commit = true; |
| 19468 | |
| 19469 | LOCK_ZONE(zone); |
| 19470 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); |
| 19471 | zone_needdump(zone, 30); |
| 19472 | UNLOCK_ZONE(zone); |
| 19473 | } |
| 19474 | |
| 19475 | failure: |
| 19476 | if (dns_rdataset_isassociated(&prdataset)) { |
| 19477 | dns_rdataset_disassociate(&prdataset); |
| 19478 | } |
| 19479 | if (dns_rdataset_isassociated(&nrdataset)) { |
| 19480 | dns_rdataset_disassociate(&nrdataset); |
| 19481 | } |
| 19482 | if (node != NULL) { |
| 19483 | dns_db_detachnode(db, &node); |
| 19484 | } |
| 19485 | if (oldver != NULL) { |
| 19486 | dns_db_closeversion(db, &oldver, false); |
| 19487 | } |
| 19488 | if (newver != NULL) { |
| 19489 | dns_db_closeversion(db, &newver, commit); |
| 19490 | } |
| 19491 | if (db != NULL) { |
| 19492 | dns_db_detach(&db); |
| 19493 | } |
| 19494 | if (commit) { |
| 19495 | LOCK_ZONE(zone); |
| 19496 | resume_addnsec3chain(zone); |
| 19497 | UNLOCK_ZONE(zone); |
| 19498 | } |
| 19499 | dns_diff_clear(&diff); |
| 19500 | isc_event_free(&event); |
| 19501 | dns_zone_idetach(&zone); |
| 19502 | |
| 19503 | INSIST(oldver == NULL); |
| 19504 | INSIST(newver == NULL); |
| 19505 | } |
| 19506 | |
| 19507 | /* |
| 19508 | * Called when an "rndc signing -nsec3param ..." command is received. |
| 19509 | * |
| 19510 | * Allocate and prepare an nsec3param_t structure which holds information about |
| 19511 | * the NSEC3 changes requested for the zone: |
| 19512 | * |
| 19513 | * - if NSEC3 is to be disabled ("-nsec3param none"), only set the "nsec" |
| 19514 | * field of the structure to true and the "replace" field to the value |
| 19515 | * of the "replace" argument, leaving other fields initialized to zeros, to |
| 19516 | * signal that the zone should be signed using NSEC instead of NSEC3, |
| 19517 | * |
| 19518 | * - otherwise, prepare NSEC3PARAM RDATA that will eventually be inserted at |
| 19519 | * the zone apex, convert it to a private-type record and store the latter |
| 19520 | * in the "data" field of the nsec3param_t structure. |
| 19521 | * |
| 19522 | * Once the nsec3param_t structure is prepared, post an event to the zone's |
| 19523 | * task which will cause setnsec3param() to be called with the prepared |
| 19524 | * structure passed as an argument. |
| 19525 | */ |
| 19526 | isc_result_t |
| 19527 | dns_zone_setnsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags, |
| 19528 | uint16_t iter, uint8_t saltlen, |
| 19529 | unsigned char *salt, bool replace) |
| 19530 | { |
| 19531 | isc_result_t result = ISC_R_SUCCESS; |
| 19532 | dns_rdata_nsec3param_t param; |
| 19533 | dns_rdata_t nrdata = DNS_RDATA_INIT; |
| 19534 | dns_rdata_t prdata = DNS_RDATA_INIT; |
| 19535 | unsigned char nbuf[DNS_NSEC3PARAM_BUFFERSIZE]; |
| 19536 | struct np3event *npe; |
| 19537 | nsec3param_t *np; |
| 19538 | dns_zone_t *dummy = NULL; |
| 19539 | isc_buffer_t b; |
| 19540 | isc_event_t *e; |
| 19541 | |
| 19542 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19543 | REQUIRE(salt != NULL); |
| 19544 | |
| 19545 | LOCK_ZONE(zone); |
| 19546 | |
| 19547 | e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_SETNSEC3PARAM, |
| 19548 | setnsec3param, zone, sizeof(struct np3event)); |
| 19549 | if (e == NULL) { |
| 19550 | result = ISC_R_NOMEMORY; |
| 19551 | goto failure; |
| 19552 | } |
| 19553 | |
| 19554 | npe = (struct np3event *) e; |
| 19555 | np = &npe->params; |
| 19556 | |
| 19557 | np->replace = replace; |
| 19558 | if (hash == 0) { |
| 19559 | np->length = 0; |
| 19560 | np->nsec = true; |
| 19561 | } else { |
| 19562 | param.common.rdclass = zone->rdclass; |
| 19563 | param.common.rdtype = dns_rdatatype_nsec3param; |
| 19564 | ISC_LINK_INIT(¶m.common, link); |
| 19565 | param.mctx = NULL; |
| 19566 | param.hash = hash; |
| 19567 | param.flags = flags; |
| 19568 | param.iterations = iter; |
| 19569 | param.salt_length = saltlen; |
| 19570 | param.salt = salt; |
| 19571 | isc_buffer_init(&b, nbuf, sizeof(nbuf)); |
| 19572 | CHECK(dns_rdata_fromstruct(&nrdata, zone->rdclass, |
| 19573 | dns_rdatatype_nsec3param, |
| 19574 | ¶m, &b)); |
| 19575 | dns_nsec3param_toprivate(&nrdata, &prdata, zone->privatetype, |
| 19576 | np->data, sizeof(np->data)); |
| 19577 | np->length = prdata.length; |
| 19578 | np->nsec = false; |
| 19579 | } |
| 19580 | |
| 19581 | /* |
| 19582 | * setnsec3param() will silently return early if the zone does not yet |
| 19583 | * have a database. Prevent that by queueing the event up if zone->db |
| 19584 | * is NULL. All events queued here are subsequently processed by |
| 19585 | * receive_secure_db() if it ever gets called or simply freed by |
| 19586 | * zone_free() otherwise. |
| 19587 | */ |
| 19588 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 19589 | if (zone->db != NULL) { |
| 19590 | zone_iattach(zone, &dummy); |
| 19591 | isc_task_send(zone->task, &e); |
| 19592 | } else { |
| 19593 | ISC_LIST_APPEND(zone->setnsec3param_queue, e, ev_link); |
| 19594 | e = NULL; |
| 19595 | } |
| 19596 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 19597 | |
| 19598 | failure: |
| 19599 | if (e != NULL) { |
| 19600 | isc_event_free(&e); |
| 19601 | } |
| 19602 | UNLOCK_ZONE(zone); |
| 19603 | return (result); |
| 19604 | } |
| 19605 | |
| 19606 | isc_result_t |
| 19607 | dns_zone_getloadtime(dns_zone_t *zone, isc_time_t *loadtime) { |
| 19608 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19609 | REQUIRE(loadtime != NULL); |
| 19610 | |
| 19611 | LOCK_ZONE(zone); |
| 19612 | *loadtime = zone->loadtime; |
| 19613 | UNLOCK_ZONE(zone); |
| 19614 | return (ISC_R_SUCCESS); |
| 19615 | } |
| 19616 | |
| 19617 | isc_result_t |
| 19618 | dns_zone_getexpiretime(dns_zone_t *zone, isc_time_t *expiretime) { |
| 19619 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19620 | REQUIRE(expiretime != NULL); |
| 19621 | |
| 19622 | LOCK_ZONE(zone); |
| 19623 | *expiretime = zone->expiretime; |
| 19624 | UNLOCK_ZONE(zone); |
| 19625 | return (ISC_R_SUCCESS); |
| 19626 | } |
| 19627 | |
| 19628 | isc_result_t |
| 19629 | dns_zone_getrefreshtime(dns_zone_t *zone, isc_time_t *refreshtime) { |
| 19630 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19631 | REQUIRE(refreshtime != NULL); |
| 19632 | |
| 19633 | LOCK_ZONE(zone); |
| 19634 | *refreshtime = zone->refreshtime; |
| 19635 | UNLOCK_ZONE(zone); |
| 19636 | return (ISC_R_SUCCESS); |
| 19637 | } |
| 19638 | |
| 19639 | isc_result_t |
| 19640 | dns_zone_getrefreshkeytime(dns_zone_t *zone, isc_time_t *refreshkeytime) { |
| 19641 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19642 | REQUIRE(refreshkeytime != NULL); |
| 19643 | |
| 19644 | LOCK_ZONE(zone); |
| 19645 | *refreshkeytime = zone->refreshkeytime; |
| 19646 | UNLOCK_ZONE(zone); |
| 19647 | return (ISC_R_SUCCESS); |
| 19648 | } |
| 19649 | |
| 19650 | unsigned int |
| 19651 | dns_zone_getincludes(dns_zone_t *zone, char ***includesp) { |
| 19652 | dns_include_t *include; |
| 19653 | char **array = NULL; |
| 19654 | unsigned int n = 0; |
| 19655 | |
| 19656 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19657 | REQUIRE(includesp != NULL && *includesp == NULL); |
| 19658 | |
| 19659 | LOCK_ZONE(zone); |
| 19660 | if (zone->nincludes == 0) |
| 19661 | goto done; |
| 19662 | |
| 19663 | array = isc_mem_allocate(zone->mctx, sizeof(char *) * zone->nincludes); |
| 19664 | if (array == NULL) |
| 19665 | goto done; |
| 19666 | for (include = ISC_LIST_HEAD(zone->includes); |
| 19667 | include != NULL; |
| 19668 | include = ISC_LIST_NEXT(include, link)) { |
| 19669 | INSIST(n < zone->nincludes); |
| 19670 | array[n++] = isc_mem_strdup(zone->mctx, include->name); |
| 19671 | } |
| 19672 | INSIST(n == zone->nincludes); |
| 19673 | *includesp = array; |
| 19674 | |
| 19675 | done: |
| 19676 | UNLOCK_ZONE(zone); |
| 19677 | return (n); |
| 19678 | } |
| 19679 | |
| 19680 | void |
| 19681 | dns_zone_setstatlevel(dns_zone_t *zone, dns_zonestat_level_t level) { |
| 19682 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19683 | |
| 19684 | zone->statlevel = level; |
| 19685 | } |
| 19686 | |
| 19687 | dns_zonestat_level_t |
| 19688 | dns_zone_getstatlevel(dns_zone_t *zone) { |
| 19689 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19690 | |
| 19691 | return (zone->statlevel); |
| 19692 | } |
| 19693 | |
| 19694 | static void |
| 19695 | setserial(isc_task_t *task, isc_event_t *event) { |
| 19696 | uint32_t oldserial, desired; |
| 19697 | const char *me = "setserial" ; |
| 19698 | bool commit = false; |
| 19699 | isc_result_t result; |
| 19700 | dns_dbversion_t *oldver = NULL, *newver = NULL; |
| 19701 | dns_zone_t *zone; |
| 19702 | dns_db_t *db = NULL; |
| 19703 | dns_diff_t diff; |
| 19704 | struct ssevent *sse = (struct ssevent *)event; |
| 19705 | dns_update_log_t log = { update_log_cb, NULL }; |
| 19706 | dns_difftuple_t *oldtuple = NULL, *newtuple = NULL; |
| 19707 | |
| 19708 | UNUSED(task); |
| 19709 | |
| 19710 | zone = event->ev_arg; |
| 19711 | INSIST(DNS_ZONE_VALID(zone)); |
| 19712 | |
| 19713 | ENTER; |
| 19714 | |
| 19715 | if (zone->update_disabled) |
| 19716 | goto failure; |
| 19717 | |
| 19718 | desired = sse->serial; |
| 19719 | |
| 19720 | dns_diff_init(zone->mctx, &diff); |
| 19721 | |
| 19722 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
| 19723 | if (zone->db != NULL) |
| 19724 | dns_db_attach(zone->db, &db); |
| 19725 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
| 19726 | if (db == NULL) |
| 19727 | goto failure; |
| 19728 | |
| 19729 | dns_db_currentversion(db, &oldver); |
| 19730 | result = dns_db_newversion(db, &newver); |
| 19731 | if (result != ISC_R_SUCCESS) { |
| 19732 | dns_zone_log(zone, ISC_LOG_ERROR, |
| 19733 | "setserial:dns_db_newversion -> %s" , |
| 19734 | dns_result_totext(result)); |
| 19735 | goto failure; |
| 19736 | } |
| 19737 | |
| 19738 | CHECK(dns_db_createsoatuple(db, oldver, diff.mctx, |
| 19739 | DNS_DIFFOP_DEL, &oldtuple)); |
| 19740 | CHECK(dns_difftuple_copy(oldtuple, &newtuple)); |
| 19741 | newtuple->op = DNS_DIFFOP_ADD; |
| 19742 | |
| 19743 | oldserial = dns_soa_getserial(&oldtuple->rdata); |
| 19744 | if (desired == 0U) |
| 19745 | desired = 1; |
| 19746 | if (!isc_serial_gt(desired, oldserial)) { |
| 19747 | if (desired != oldserial) |
| 19748 | dns_zone_log(zone, ISC_LOG_INFO, |
| 19749 | "setserial: desired serial (%u) " |
| 19750 | "out of range (%u-%u)" , desired, |
| 19751 | oldserial + 1, (oldserial + 0x7fffffff)); |
| 19752 | goto failure; |
| 19753 | } |
| 19754 | |
| 19755 | dns_soa_setserial(desired, &newtuple->rdata); |
| 19756 | CHECK(do_one_tuple(&oldtuple, db, newver, &diff)); |
| 19757 | CHECK(do_one_tuple(&newtuple, db, newver, &diff)); |
| 19758 | result = dns_update_signatures(&log, zone, db, |
| 19759 | oldver, newver, &diff, |
| 19760 | zone->sigvalidityinterval); |
| 19761 | if (result != ISC_R_NOTFOUND) |
| 19762 | CHECK(result); |
| 19763 | |
| 19764 | /* Write changes to journal file. */ |
| 19765 | CHECK(zone_journal(zone, &diff, NULL, "setserial" )); |
| 19766 | commit = true; |
| 19767 | |
| 19768 | LOCK_ZONE(zone); |
| 19769 | zone_needdump(zone, 30); |
| 19770 | UNLOCK_ZONE(zone); |
| 19771 | |
| 19772 | failure: |
| 19773 | if (oldtuple != NULL) |
| 19774 | dns_difftuple_free(&oldtuple); |
| 19775 | if (newtuple != NULL) |
| 19776 | dns_difftuple_free(&newtuple); |
| 19777 | if (oldver != NULL) |
| 19778 | dns_db_closeversion(db, &oldver, false); |
| 19779 | if (newver != NULL) |
| 19780 | dns_db_closeversion(db, &newver, commit); |
| 19781 | if (db != NULL) |
| 19782 | dns_db_detach(&db); |
| 19783 | dns_diff_clear(&diff); |
| 19784 | isc_event_free(&event); |
| 19785 | dns_zone_idetach(&zone); |
| 19786 | |
| 19787 | INSIST(oldver == NULL); |
| 19788 | INSIST(newver == NULL); |
| 19789 | } |
| 19790 | |
| 19791 | isc_result_t |
| 19792 | dns_zone_setserial(dns_zone_t *zone, uint32_t serial) { |
| 19793 | isc_result_t result = ISC_R_SUCCESS; |
| 19794 | dns_zone_t *dummy = NULL; |
| 19795 | isc_event_t *e = NULL; |
| 19796 | struct ssevent *sse; |
| 19797 | |
| 19798 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19799 | |
| 19800 | LOCK_ZONE(zone); |
| 19801 | |
| 19802 | if (!inline_secure(zone)) { |
| 19803 | if (!dns_zone_isdynamic(zone, true)) { |
| 19804 | result = DNS_R_NOTDYNAMIC; |
| 19805 | goto failure; |
| 19806 | } |
| 19807 | } |
| 19808 | |
| 19809 | if (zone->update_disabled) { |
| 19810 | result = DNS_R_FROZEN; |
| 19811 | goto failure; |
| 19812 | } |
| 19813 | |
| 19814 | e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_SETSERIAL, |
| 19815 | setserial, zone, sizeof(struct ssevent)); |
| 19816 | if (e == NULL) { |
| 19817 | result = ISC_R_NOMEMORY; |
| 19818 | goto failure; |
| 19819 | } |
| 19820 | |
| 19821 | sse = (struct ssevent *)e; |
| 19822 | sse->serial = serial; |
| 19823 | |
| 19824 | zone_iattach(zone, &dummy); |
| 19825 | isc_task_send(zone->task, &e); |
| 19826 | |
| 19827 | failure: |
| 19828 | if (e != NULL) |
| 19829 | isc_event_free(&e); |
| 19830 | UNLOCK_ZONE(zone); |
| 19831 | return (result); |
| 19832 | } |
| 19833 | |
| 19834 | isc_stats_t * |
| 19835 | dns_zone_getgluecachestats(dns_zone_t *zone) { |
| 19836 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19837 | |
| 19838 | return (zone->gluecachestats); |
| 19839 | } |
| 19840 | |
| 19841 | bool |
| 19842 | dns_zone_isloaded(const dns_zone_t *zone) { |
| 19843 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19844 | |
| 19845 | return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)); |
| 19846 | } |
| 19847 | |
| 19848 | isc_result_t |
| 19849 | dns_zone_verifydb(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver) { |
| 19850 | dns_dbversion_t *version = NULL; |
| 19851 | dns_keytable_t *secroots = NULL; |
| 19852 | isc_result_t result; |
| 19853 | dns_name_t *origin; |
| 19854 | |
| 19855 | const char me[] = "dns_zone_verifydb" ; |
| 19856 | ENTER; |
| 19857 | |
| 19858 | REQUIRE(DNS_ZONE_VALID(zone)); |
| 19859 | REQUIRE(db != NULL); |
| 19860 | |
| 19861 | if (dns_zone_gettype(zone) != dns_zone_mirror) { |
| 19862 | return (ISC_R_SUCCESS); |
| 19863 | } |
| 19864 | |
| 19865 | if (ver == NULL) { |
| 19866 | dns_db_currentversion(db, &version); |
| 19867 | } else { |
| 19868 | version = ver; |
| 19869 | } |
| 19870 | |
| 19871 | if (zone->view != NULL) { |
| 19872 | result = dns_view_getsecroots(zone->view, &secroots); |
| 19873 | if (result != ISC_R_SUCCESS) { |
| 19874 | goto done; |
| 19875 | } |
| 19876 | } |
| 19877 | |
| 19878 | origin = dns_db_origin(db); |
| 19879 | result = dns_zoneverify_dnssec(zone, db, version, origin, secroots, |
| 19880 | zone->mctx, true, false); |
| 19881 | |
| 19882 | done: |
| 19883 | if (secroots != NULL) { |
| 19884 | dns_keytable_detach(&secroots); |
| 19885 | } |
| 19886 | |
| 19887 | if (ver == NULL) { |
| 19888 | dns_db_closeversion(db, &version, false); |
| 19889 | } |
| 19890 | |
| 19891 | if (result != ISC_R_SUCCESS) { |
| 19892 | dnssec_log(zone, ISC_LOG_ERROR, "zone verification failed: %s" , |
| 19893 | isc_result_totext(result)); |
| 19894 | result = DNS_R_VERIFYFAILURE; |
| 19895 | } |
| 19896 | |
| 19897 | return (result); |
| 19898 | } |
| 19899 | |